Contents Purpose Anatomy Variants States Tokens Used Accessibility Behavior Platform Notes Component: tag Purpose Display a categorical label. Optionally interactive (filterable, removable). Anatomy label — required, text content remove — optional, dismiss/remove button (x icon) Variants Class Visual Usage tag Base class — surface-tertiary bg, text-secondary Neutral category label tag-accent accent-subtle bg, accent-text Highlighted or active category States Non-interactive by default. A tag is display-only unless it is an <a>, <button>, or contains a remove button. Interactive tags (a.tag, button.tag): Hover (transition: --duration-normal ease-out): tag: background-color → one step darker (use --color-border-default as hover bg) tag-accent: background-color → --color-accent-muted Active (instant): tag: background-color → --color-border-emphasis tag-accent: background-color → --color-accent-muted (same — the step is subtle) Focus-visible (interactive tags only): outline: 2px solid var(--color-accent-base) outline-offset: 2px Selected (is-selected class, for filterable tags toggled on): background-color: var(--color-accent-subtle) border-left: 2px solid var(--color-accent-base) padding-left adjusted to compensate for border width Remove button (.tag-remove): Inline button within the tag Inherits tag text color, hover shifts to --color-text-primary Focus-visible gets its own outline Size: --icon-sm (16px) Tokens Used --font-sans, --text-sm, --leading-normal --space-1, --space-2 --color-surface-tertiary --color-text-secondary, --color-text-primary --color-accent-subtle, --color-accent-muted, --color-accent-base, --color-accent-text --color-border-default, --color-border-emphasis --duration-normal --icon-sm Accessibility Display-only tags: use <span class="tag"> Filterable tags: use <button class="tag"> with aria-pressed for toggle state Linked tags: use <a class="tag"> Remove button: aria-label="Remove {tag label}" Keyboard: interactive tags activated by Enter/Space; remove button is a separate tab stop Minimum target size: remove button meets 32px via padding Behavior Tags do not truncate — if the label is too long, it wraps. Remove button click/activation removes the tag from the DOM (JS responsibility). is-selected is toggled by JS for filterable tag sets. Platform Notes Web: CSS in @layer components. Non-interactive tags have no cursor change. Interactive tags get cursor: pointer. macOS: Map to a styled capsule view or SwiftUI Label with appropriate interaction modifiers.