Description
Displays a short text label that represents a classification, keyword, or filter applied to a record or content item. Tags are interactive — they can be dismissed or removed by the user, distinguishing them from static labels.
Filter bars on stakeholder lists and consultation records in Open Point; topic and interest filters on community engagement pages in Social Point; keyword labels on uploaded documents, submissions, and reports.
Government users need to apply and manage multiple classifications to records (e.g. 'Transport', 'Urgent', 'Phase 2'). Tags provide a scannable, removable representation of those classifications without cluttering the primary content area.
Anatomy
| Part | Required? | Notes |
|---|---|---|
| Container | Required | Rounded pill or chip shape housing all tag content. Uses --op-radius-pill or --op-radius-md depending on variant. |
| Label text | Required | Short plain-language string identifying the classification. Truncates with ellipsis at a max-width; full value shown on hover via tooltip. |
| Remove button | Optional | An icon button (close icon) that dismisses the tag. Required when tags are user-removable. Must be keyboard-accessible and have a visually hidden descriptive label. |
| Leading icon | Optional | A small decorative or semantic icon preceding the label text. Use only when it adds meaningful context (e.g. a category icon). |
Variants
Default
Neutral classification or keyword
Use for user-applied or system-assigned labels that do not carry a status meaning. Suitable for topic tags, keyword filters, and record classifications.
Removable
Active filter or user-applied label that can be dismissed
Use when the tag represents an active filter or selection that the user can clear. Always include a visible remove button and accessible label.
Outlined
Lower-visual-weight classification
Use when tags appear alongside heavier UI elements and need to recede visually. Suitable for secondary metadata in detail panels.
States
| State | Behaviour |
|---|---|
| Default | Tag is visible and static. Remove button (if present) is visible but not active. |
| Hover | Remove button background transitions to --op-color-interactive-hover. Cursor changes to pointer over the remove button. |
| Focus | Focus ring (3px solid --op-color-interactive-focus) appears on the remove button. Focus is not placed on the tag container itself unless the tag is also clickable. |
| Disabled | Tag and remove button are non-interactive. Opacity reduced to 40%. Remove button is not focusable. Use sparingly — prefer hiding tags that cannot be acted on. |
| Loading/pending removal | After remove button is activated, tag can briefly show a spinner in place of the close icon to indicate async removal before disappearing. |
Usage guidelines
When to use
- Displaying user-applied classifications on a stakeholder record, e.g. 'Transport', 'Media', 'High priority'.
- Showing active filters in a filter bar above a list of consultations or submissions.
- Representing interest topics selected by a community member on their Social Point profile.
- Labelling uploaded documents with content categories before submission.
When not to use
- Displaying read-only status values such as 'Active', 'Closed', or 'Draft' — use Badge instead.
- Navigating between views or sections — use tabs or links.
- Representing a single boolean state (on/off) — use a Checkbox or Switch.
- Long multi-word labels — tags are designed for short strings (1–3 words). Truncate or rephrase if needed.
Do / Don't
Do
Keep tag labels short (1–3 words). Use sentence case.
Don't
Don't use full sentences or punctuation inside a tag label.
Do
Provide a descriptive accessible label on the remove button, e.g. 'Remove Transport tag'.
Don't
Don't use a bare times character as the only accessible label for the remove action.
Do
Group related tags in a horizontal wrapping row with consistent spacing (--op-space-8 gap).
Don't
Don't mix Tag and Badge in the same row to represent the same type of information — pick one.
Do
Announce tag removal to screen readers using an ARIA live region.
Don't
Don't silently remove a tag without any feedback to assistive technology users.
Layout & Spacing
Tag container: padding --op-space-4 (4px) vertical, --op-space-8 (8px) horizontal. Gap between label and remove button: --op-space-4 (4px). Gap between tags in a tag group: --op-space-8 (8px). Minimum height: 28px (desktop); 44px touch targets apply to the remove button, not the container. Max-width: 200px with text-overflow: ellipsis.
Tokens
| Part | Token | Value |
|---|---|---|
| Container background (default) | --op-color-bg-subtle | Light neutral fill; adapts to light/dark themes. |
| Container background (outlined) | transparent | Border only; no fill. |
| Container border | --op-color-border-default | 1px solid border on outlined variant; none on default. |
| Label text | --op-color-text-primary | High-contrast label text; --op-text-sm size. |
| Label font size | --op-text-sm | Approximately 14px. |
| Remove button icon | --op-color-text-secondary | Slightly muted to avoid competing with label text. |
| Remove button hover background | --op-color-interactive-hover | Applied to the button element, not the tag container. |
| Focus ring | --op-color-interactive-focus | 3px solid outline on remove button focus. |
| Disabled opacity | 0.4 | Applied to the entire tag container when disabled. |
| Border radius | --op-radius-pill | Use --op-radius-md for a more rectangular chip style if required by product. |
Engineering notes
- Use the `wa-tag` Web Awesome component where available. Set `removable` attribute to render the remove button.
- The remove button must fire a custom event (e.g. `wa-remove`) that the parent component listens to. Never remove the tag from the DOM directly inside the component.
- Wrap a set of tags in a `` with each tag as `` to provide list semantics for screen readers.
- Maintain an ARIA live region (`aria-live='polite'`) adjacent to the tag group. When a tag is removed, announce e.g. 'Transport tag removed. 3 tags remaining.'
- When tags represent active filters, the tag group should be labelled with `aria-label='Active filters'` or associated with a visible heading via `aria-labelledby`.
- For async removal (e.g. API call on remove), replace the close icon with `wa-spinner` and set `aria-busy='true'` on the tag until the operation resolves.
- Avoid hardcoded max-widths in component styles; let consuming layouts constrain width via a wrapping container.
Keyboard interaction
Key Action Tab Moves focus to the remove button within a tag (the tag container itself is not focusable unless also used as a button). Enter Activates the focused remove button, triggering tag removal. Space Activates the focused remove button (same as Enter for button elements). Shift+Tab Moves focus to the previous interactive element (prior tag's remove button or the element before the tag group). Why it matters
Government platforms serve users who rely on keyboard navigation and screen readers, including users with motor impairments and visual impairments. Tags used as active filters directly affect what data a user sees — inaccessible removal controls can prevent users from modifying their own search or filter state, which is a significant barrier in administrative tools.
Focus
Focus is placed on the remove button element within each tag, not on the tag container. Focus ring: 3px solid --op-color-interactive-focus, with a 2px offset to prevent clipping by the container border. When a tag is removed via keyboard, focus should move to the next tag's remove button, or to the preceding tag if the removed tag was last, or to the filter input if no tags remain. prefers-reduced-motion: transition animations on removal should be suppressed.
ARIA
Role or attribute When to use Example role='list' / role='listitem'Applied to the tag group container and each tag respectively, to communicate group semantics. <div role="list" aria-label="Active filters"><div role="listitem">...</div></div>aria-label on remove buttonProvides a descriptive label that includes the tag value, since the visible icon alone is insufficient. <button aria-label="Remove Transport tag"><wa-icon name="xmark"></wa-icon></button>aria-liveAnnounces tag removal to screen readers without moving focus unexpectedly. <div aria-live="polite" aria-atomic="true" class="sr-only"></div>aria-disabledUsed on the tag container when the tag is in a disabled state. Do not use the HTML disabled attribute on non-form elements. <div role="listitem" aria-disabled="true">...</div>aria-busySet on the tag during async removal to indicate a pending operation. <div role="listitem" aria-busy="true">...</div>Contrast
Label text (--op-color-text-primary) on tag background (--op-color-bg-subtle): must meet 4.5:1 for --op-text-sm. Remove icon (--op-color-text-secondary) on tag background: must meet 3:1 as a UI component (WCAG 1.4.11). Outlined variant: border (--op-color-border-default) against surrounding background must meet 3:1. Focus ring (--op-color-interactive-focus) against adjacent background: must meet 3:1. Disabled state at 40% opacity will fail contrast — this is an accepted pattern for disabled controls, but avoid disabling tags unless strictly necessary.
Touch targets
The tag container does not require a 44x44px touch target. The remove button does. Ensure the remove button has a minimum tap target of 44x44px using padding or a transparent hit-area pseudoelement, even if the visual icon is smaller (e.g. 16x16px).
Things to avoid
- Do not rely on colour alone to distinguish tag types or states — always pair with a text label or icon.
- Do not place focus on the tag container if it is not interactive; only the remove button should receive focus.
- Do not suppress focus styles for any interactive element within the tag, including the remove button.
- Do not remove a tag from the DOM without announcing the change via an ARIA live region.
- Do not use title attributes as a substitute for aria-label on the remove button.