Skip to content

Tag Group

Data displaySince 0.9.0
import { TagGroup } from '@absoluteui/components/tag-group';
import '@absoluteui/components/tag-group/style.css';

Using Angular? See Tag Group for Angular.

Interactive tags such as applied filters, recipients, or labels on a record: removable, selectable (single or multiple), or both. The tags form a grid with one row per tag, as in the React Aria TagGroup: one tag is in the tab sequence, the arrow keys move between tags, Space selects, and Delete or Backspace removes. Static labels are Badge.

  • Applied filters the user can remove one by one.
  • A short set of labels the user selects to filter or categorize.
  • Recipients or assignees shown as removable chips.
  • Static status or category labels: use Badge.
  • Choosing values in a form field: use Multi Select (its chips are part of the field).
  • Navigation: use Tabs or links.
import { TagGroup, type TagGroupRemoveDetail } from '@absoluteui/components/tag-group';
const host = document.createElement('div');
const status = document.createElement('p');
document.body.append(host, status);
const filters = TagGroup.create(host, {
label: 'Applied filters',
removable: true,
items: [
{ value: 'london', label: 'Location: London' },
{ value: 'remote', label: 'Remote' },
{ value: 'senior', label: 'Level: Senior' },
],
});
host.addEventListener('aui-remove', (event) => {
const { item } = (event as CustomEvent<TagGroupRemoveDetail>).detail;
status.textContent = `${String(filters.items.length - 1)} filters applied (removed ${item.label})`;
});
import { TagGroup, type TagGroupChangeDetail } from '@absoluteui/components/tag-group';
const host = document.createElement('div');
const result = document.createElement('p');
document.body.append(host, result);
TagGroup.create(host, {
label: 'Categories',
selection: 'multiple',
value: ['design'],
items: [
{ value: 'design', label: 'Design' },
{ value: 'engineering', label: 'Engineering' },
{ value: 'sales', label: 'Sales' },
{ value: 'legal', label: 'Legal', disabled: true },
],
});
host.addEventListener('aui-change', (event) => {
result.textContent = `Showing: ${(event as CustomEvent<TagGroupChangeDetail>).detail.value.join(', ') || 'all'}`;
});
import { TagGroup } from '@absoluteui/components/tag-group';
import '@absoluteui/components/tag-group/style.css';
const host = document.querySelector<HTMLElement>('#labels');
if (host) TagGroup.create(host, { label: 'Labels', items: [{ value: 'bug', label: 'Bug' }, { value: 'ui', label: 'UI' }], removable: true });
import { TagGroup, type TagGroupRemoveDetail } from '@absoluteui/components/tag-group';
const host = document.querySelector<HTMLElement>('#recipients');
if (host) {
const recipients = TagGroup.create(host, { label: 'Recipients', removable: true, items: [{ value: 'ada', label: 'Ada Lovelace' }, { value: 'grace', label: 'Grace Hopper' }] });
host.addEventListener('aui-remove', (event) => {
const { value } = (event as CustomEvent<TagGroupRemoveDetail>).detail;
if (recipients.items.length === 1) event.preventDefault(); // keep at least one recipient
else console.info(`removed ${value}`);
});
}
<div class="aui-tag-group aui-tag-group--{size}" role="grid" aria-label="Applied filters" [aria-multiselectable]>
<div class="aui-tag-group__tag [--selected]" role="row" tabindex="0|-1" [aria-selected] [aria-disabled]>
<div class="aui-tag-group__cell" role="gridcell">
<span class="aui-tag-group__label">London</span>
<button class="aui-tag-group__remove" tabindex="-1" aria-label="Remove London">icon</button> (removable)
</div>
</div>
...
</div>
TagGroup.create(host: HTMLElement, options: TagGroupOptions): TagGroup

Global configuration key: tagGroup (see Configuration).

Option Type Default Description
label string Accessible name of the group. Required.
items readonly TagGroupItem[] Tags: { value, label, disabled? } (unique values, at most 1,000). Required.
removable boolean "false" Remove button per tag; Delete and Backspace remove the focused tag.
selection 'none' | 'single' | 'multiple' "none" Selection mode.
value readonly string[] Selected values.
size 'sm' | 'md' "md" Tag size. Globally configurable.
icons Partial<TagGroupIcons> Icon slot overrides.
locale string "en-US" Locale of the remove label and announcement. Globally configurable. Inherited from common configuration.
Property Type Description
host HTMLElement The host element (role=grid while it has tags).
items readonly TagGroupItem[] The tags shown, after removals.
value readonly string[] Selected values, in tag order.
options Readonly<TagGroupOptions> Current options.
Method Description
setValue(value: readonly string[]): void Set the selected values (no event).
focus(): void Focus the tag in the tab sequence.
update(options: Partial<TagGroupOptions>): void Merge and apply options; focus stays on the same tag.
destroy(): void Remove rendering, attributes, and listeners.
Event Detail Bubbles Cancelable Description
aui-change TagGroupChangeDetail Yes No The user changed the selection (or removed a selected tag): { value }.
aui-remove TagGroupRemoveDetail Yes Yes The user removes a tag: { value, item }. Prevent it to keep the tag.

All rules live in the aui.components cascade layer, so application styles override them without specificity battles.

Class Purpose
aui-tag-group Host.
aui-tag-group--sm | --md Size modifiers.
aui-tag-group__tag A tag (role=row).
aui-tag-group__tag--selected A selected tag.
aui-tag-group__cell The tag’s gridcell.
aui-tag-group__label Tag text.
aui-tag-group__remove Remove button.
Slot Default icon
remove close

Tokens this stylesheet reads (verified in CI). Override them in a theme or with the Theme Designer.

--aui-border-width | --aui-color-border-strong | --aui-color-focus-ring | --aui-color-hover | --aui-color-selected | --aui-color-selected-indicator | --aui-color-selected-text | --aui-color-surface | --aui-color-text | --aui-color-text-disabled | --aui-color-text-muted | --aui-duration-fast | --aui-easing-standard | --aui-focus-ring-offset | --aui-focus-ring-width | --aui-font-family-sans | --aui-font-size-sm | --aui-font-size-xs | --aui-icon-size-sm | --aui-line-height-tight | --aui-radius-pill | --aui-space-1 | --aui-space-2 | --aui-space-3

type TagGroupSelection = 'none' | 'single' | 'multiple';
type TagGroupSize = 'sm' | 'md';
interface TagGroupConfig { size: TagGroupSize }
interface TagGroupItem { value: string; label: string; disabled?: boolean }
interface TagGroupIcons { remove: IconRef }
interface TagGroupOptions extends Partial<TagGroupConfig> {
label: string;
items: readonly TagGroupItem[];
removable?: boolean;
selection?: TagGroupSelection;
value?: readonly string[];
locale?: string;
icons?: Partial<TagGroupIcons>;
}
interface TagGroupChangeDetail { value: string[] }
interface TagGroupRemoveDetail { value: string; item: TagGroupItem }

Pattern: Grid list (as in the React Aria TagGroup): role=grid with one row per tag and one gridcell per row; roving tabindex over the rows.

Key Context Action
Tab Group Moves into the group (to the last focused tag) and out of it.
Arrow keys Tag Move to the next or previous enabled tag (reading direction aware).
Home / End Tag First or last enabled tag.
Space / Enter Tag (selection enabled) Select or deselect the tag.
Delete / Backspace Tag (removable) Remove the tag; focus moves to the next tag, or the previous one at the end.
Element Role
host grid (absent while empty)
tag row
tag content gridcell
remove button (native, tabindex -1)
Attribute Element Value
aria-label host the label option
aria-multiselectable host true with selection ‘multiple’
aria-selected tag true or false when selection is enabled; absent otherwise
aria-disabled tag true for disabled tags
aria-label remove ‘Remove {label}’ (localized)

One tag in the tab sequence; after a removal, focus moves to the tag that took its place (or the previous tag).

Criterion Level Note
1.3.1 Info and Relationships A
1.4.1 Use of Color A
2.1.1 Keyboard A
2.4.3 Focus Order A
4.1.2 Name, Role, Value A
4.1.3 Status Messages AA

Automated test results: Accessibility and compliance.

  • Removals are announced (‘{label} removed’) through the polite live region.
  • Selected tags differ in more than hue (selection fill and a stronger boundary).
  • Grid semantics are announced differently by screen readers; manual verification (NVDA, JAWS, VoiceOver) is pending.

Removable; selection none, single, or multiple; selected; disabled tag; sizes sm and md; empty.

From Trigger To
tag shown Delete, Backspace, or the remove button aui-remove; unless prevented, the tag is removed, focus moves on, and “{label} removed” is announced
unselected Space, Enter, or click (selection enabled) selected; aui-change
selected Space, Enter, or click unselected; aui-change
single, A selected select B B selected, A unselected
  • Removals are announced through the polite live region.
  • When the last tag is removed, focus has nowhere to go inside the group: move it in an aui-remove handler.
  • Selected tags differ in more than hue.
  • The e2e axe run covers three themes; manual screen-reader verification is pending.

Tags wrap onto several lines; long labels are truncated with an ellipsis.

Arrow keys follow the reading direction; the remove button sits at the inline end.

The tag tokens and the selection colors are in the contrast gate. Forced colors draw selected tags in Highlight.

configureAbsoluteUI({ components: { tagGroup: { size: 'sm' } } });

Instance size and locale override configuration; configuration changes re-render existing groups.

icons.remove (default close).

Labels use textContent; they are never parsed as HTML.

No persistence, network access, or telemetry. A removal changes only the displayed tags; update your own data from aui-remove.

Each change re-creates the tag elements and restores focus to the same tag.

Up to 1,000 tags; intended for tens.

  • update({ items }) keeps focus on the same tag when it still exists.
  • A disabled tag cannot be selected or removed; the arrow keys skip it.
  • An empty group has no grid role and no aria-label (a grid needs rows, and a name needs a role).
Code Category Cause
TAG_GROUP_OPTIONS configuration Blank label, items that are not an array (or more than 1,000), duplicate or blank values, a blank tag label, an unknown selection mode, or several values with single.
ICON_UNKNOWN configuration Unknown remove icon.
CFG_INVALID_VALUE / CFG_UNKNOWN_OPTION configuration Invalid size, locale, or unknown configuration.

Invalid options throw before the host is modified; an invalid update() leaves the previous state intact.

  • Removing the last tag leaves focus on the page body.
  • Manual screen-reader verification is pending.
  • Editing a tag in place.
  • Rich content in tags.