Role and semantics
Section titled “Role and semantics”- A static Tag is a plain
<span>; it has no role and its text is read in flow. - A selectable Tag is a real
<button>built with the Base UIToggle.aria-pressedcarries its state; the check mark is decorative (aria-hidden). - On a removable Tag the remove button is a real
<button>. Its name comes from the library string: “Remove Design” or “Tasarım kaldır”.removeLabelreplaces the name. Tag.Groupis a named list (role="list", requiredaria-label); each tag sits in alistitem. The explicit role keeps Safari from dropping the list when its list style is removed.- Icons (
icon, the × mark, the check mark) are decorative and hidden from screen readers.
Keyboard
Section titled “Keyboard”| Key | Behaviour |
|---|---|
| Tab | Each remove button and each selectable tag is its own tab stop. A static tag takes no focus. |
| Enter, Space | Toggles a selectable tag; removes the tag while the remove button has focus. |
| Backspace, Delete | Removes the tag while the remove button has focus. |
There is no arrow-key navigation. When a tag in a Tag.Group is removed, focus moves to the next tag’s remove button, else the previous one, else the onEmpty target (or the group when none is given); focus never falls back to the top of the page.
The focus ring is drawn on the interactive element itself: around the selectable tag or around the remove button, 2 px wide and 2 px away. The ring shows for keyboard focus only.
Screen reader output
Section titled “Screen reader output”| Example | Read |
|---|---|
| Static tag | “Label” |
| Removable tag | “Design”; then “Remove Design, button” |
| Selectable tag, selected | “Design, button, pressed” |
| Selectable tag, not selected | “Design, button, not pressed” |
| Tag group | “Labels, list, 3 items” |
Contrast
Section titled “Contrast”Text is at least 4.5:1 in every brand and mode; values are computed from the bigbang token output.
| Pair | Light mode | Dark mode |
|---|---|---|
color-text-default / color-surface-default (neutral) |
16.16:1 | 17.18:1 |
color-status-brand-foreground / color-status-brand-background (selected) |
7.53:1 | 9.24:1 |
color-status-info-foreground / color-surface-default |
8.63:1 | 8.91:1 |
color-status-success-foreground / color-surface-default |
6.87:1 | 10.09:1 |
color-status-warning-foreground / color-surface-default |
6.72:1 | 10.60:1 |
color-status-danger-foreground / color-surface-default |
7.23:1 | 8.83:1 |
color-focus-ring / color-surface-default (lowest) |
5.97:1 | 8.09:1 |
The neutral border (color-border-default, 1.38:1) is decorative: the text identifies the tag. Disabled text (color-text-disabled, 2.52:1) falls under the WCAG 1.4.3 exception for disabled components.
WCAG 2.2
Section titled “WCAG 2.2”| Criterion | How Tag meets it | What the product team does |
|---|---|---|
| 1.3.1 Info and relationships | The group is a list, tags are listitem; the selected state is aria-pressed. |
Give tag groups a meaningful aria-label. |
| 1.4.1 Use of colour | The text carries the meaning; the tone only emphasises. A selected tag also shows a check mark. | Do not rely on colour alone for a tag. |
| 1.4.3 Contrast (minimum) | Every tone is at least 6.72:1. | Do not add custom colours; use tone. |
| 2.1.1 Keyboard | Works with Tab, Enter, Space, Backspace and Delete. | Do not make removal mouse-only. |
| 2.4.3 Focus order | After removal focus moves to the neighbouring tag’s button. | Provide an onEmpty target when the last tag can be removed. |
| 2.4.7 Focus visible | The ring is at least 5.97:1. | Do not remove outline with className. |
| 2.5.8 Target size | The remove button is 24 x 24 px; a selectable tag is at least 24 px tall. | Do not squeeze size="sm" tags together; keep the 8 px gap. |
| 4.1.2 Name, role, value | Buttons have a name and an aria-pressed value. |
Keep the tag name when you set removeLabel. |