Tag
How the Tag works with a keyboard and assistive tech, and where it stands against WCAG 2.2 AA.
A Tag shows a value. On its own it is text in a <span>; what makes it interactive are its parts. The dismiss cross is a real <button> named "Remove {label}", and a Tag 2.0 given onToggle wraps its body in a <button> with aria-pressed. Everything else is presentation.
Keyboard#
Moves to the next interactive part: a selectable tag's body, then its dismiss button. A plain tag without either is skipped.
Moves to the previous interactive part.
On the body of a selectable tag: toggles it. On the cross: removes the tag.
Same as Enter, on key release.
Semantics#
<span>Plain text. Its leading icon, flag, logo or avatar is decorative (alt="", aria-hidden).
Static tag<button aria-pressed>Selected is announced as pressed. An icon-only tag gets aria-label from its label.
Tag 2.0 with onToggle<button aria-label="Remove …">The cross is a separate button. Without onDismiss it is drawn but hidden (aria-hidden) and does nothing.
Dismissiblearia-disabledOn the tag; its buttons are disabled and leave the tab order.
DisabledSelected (Tag 1.0)Visual only. Tag 1.0 has no toggle, so nothing tells assistive tech it is selected.
state="selected"Colour contrast#
Every variant and state has to meet WCAG 2.2 Level AA. Measure the colours as they land on screen: a translucent hover or press wash over whatever sits behind it.
Label and sub-label · Default, Hover, Selected
Satoshi 12 is small text, so 4.5:1 in every state. Washes are measured over white.
WCAG 1.4.3 Contrast (Minimum) ↗Dismiss cross · Dismissible
The cross is the only sign of the remove button, so it needs 3:1: #6d6d6d on white measures 5.17:1, and white on brand 5.40:1.
WCAG 1.4.11 Non-text Contrast ↗Focus indicator · Focus visible
A 2px ring in #1a6ef8 (4.54:1 on white). Tag 2.0 draws it outside the tag with a 1px white gap; the cross rings itself.
WCAG 1.4.11 Non-text Contrast ↗WCAG 2.4.13 Focus Appearance ↗Target size · Dismiss
The cross is 12px (1.0) or 14px (2.0) but its hit area is padded to 24px and 26px.
WCAG 2.5.8 Target Size (Minimum) ↗Measured contrast#
Label and sub-label against the tag in each state, measured on white from the tag tokens. Disabled is grey on grey and exempt as an inactive control. 8 of 18 pairs fall below their minimum (4.5:1 for text, 3:1 for graphics) and are marked in amber.
Motion#
- Colour changes between states take 150ms and are turned off under prefers-reduced-motion.
Checklist#
When a tag is removed, move focus to the next tag, or to the field if it was the last. The component does not; without it focus drops to the page.
Use Tag 2.0 with onToggle for filters, so selected is announced. A Tag 1.0 in its selected state only looks selected.
Sub-labels in #8f8f8f measure about 3.2:1 on white and less on a wash, and the selected 2.0 sub-label is 2.9:1. Darken them, or keep counts in the label.
Name the remove button after the value ("Remove Design"), not "Remove tag". Pass dismissAriaLabel when the label is not plain text.
