Reka UI logoReka
backdrop
Components

Tag Group

Alpha
A focusable list of tags that can be navigated, selected and removed with the keyboard. Useful for categories, applied filters, or values picked from another control.
Apple
Banana
Blueberry
Grape

Features

  • Full keyboard navigation, including typeahead.
  • Supports no, single or multiple selection.
  • Removable with the keyboard or a delete button.
  • Keeps focus on a neighbouring tag after removal.
  • Can be controlled or uncontrolled.
  • Labelled and described by an ancestor Field.

Installation

Install the component from your command line.

sh
$ npm add reka-ui

Anatomy

Import all parts and piece them together.

vue
<script setup>
import { TagGroupItem, TagGroupItemDelete, TagGroupItemText, TagGroupRoot } from 'reka-ui'
</script>

<template>
  <TagGroupRoot>
    <TagGroupItem>
      <TagGroupItemText />
      <TagGroupItemDelete />
    </TagGroupItem>
  </TagGroupRoot>
</template>

API Reference

Root

Contains all the tags. Renders a grid, or a group when there are no tags.

Data AttributeValue
[data-disabled]Present when disabled
[data-empty]Present when there are no tags

Item

A tag. Pressing Delete or Backspace on it removes it.

Data AttributeValue
[data-state]"checked" | "unchecked"
[data-disabled]Present when disabled

ItemText

The text of the tag. Used for typeahead unless the item has a textValue.

ItemDelete

The button that removes its tag. It is labelled "Remove" followed by the tag's name; pass an aria-label to translate it.

Data AttributeValue
[data-disabled]Present when disabled

Examples

Removing tags

Tags are removable when you listen to the remove event. It receives the values to remove, which you remove from your own list. Removing a selected tag with the keyboard removes every selected tag.

vue
<script setup>
import { ref } from 'vue'

const tags = ref(['News', 'Travel', 'Gaming'])
function onRemove(values) {
  tags.value = tags.value.filter(tag => !values.includes(tag))
}
</script>

<template>
  <TagGroupRoot aria-label="Categories" @remove="onRemove">
    <TagGroupItem v-for="tag in tags" :key="tag" :value="tag">
      <TagGroupItemText></TagGroupItemText>
      <TagGroupItemDelete>×</TagGroupItemDelete>
    </TagGroupItem>
  </TagGroupRoot>
</template>

Selection

Set selectionMode to single or multiple to make tags selectable with a click, Space or Enter. v-model holds the selected value, or an array of values when multiple.

vue
<template>
  <TagGroupRoot v-model="selected" selection-mode="multiple" aria-label="Amenities">
    <TagGroupItem v-for="amenity in amenities" :key="amenity" :value="amenity">
      <TagGroupItemText></TagGroupItemText>
    </TagGroupItem>
  </TagGroupRoot>
</template>

Empty state

When there are no tags, the root renders as a focusable group with a data-empty attribute. Render any empty content inside it.

vue
<template>
  <TagGroupRoot aria-label="Categories" @remove="onRemove">
    <TagGroupItem v-for="tag in tags" :key="tag" :value="tag">
      <TagGroupItemText></TagGroupItemText>
    </TagGroupItem>
    <span v-if="!tags.length">No categories</span>
  </TagGroupRoot>
</template>

With a label and description

Place the root in a FieldRoot to label and describe it.

vue
<template>
  <FieldRoot>
    <FieldLabel :native-label="false">
      Categories
    </FieldLabel>
    <TagGroupRoot @remove="onRemove">
      <!-- ... -->
    </TagGroupRoot>
    <FieldDescription>Your selected categories.</FieldDescription>
  </FieldRoot>
</template>

Accessibility

Adheres to the Grid WAI-ARIA design pattern, with each tag a row. When using asChild on TagGroupItem, wrap the tag's content in an element with role="gridcell".

Keyboard Interactions

KeyDescription
Tab
Moves focus into the tag group, to the focused tag's delete button, then out of the tag group.
ArrowRightArrowDown
Moves focus to the next tag.
ArrowLeftArrowUp
Moves focus to the previous tag.
HomeEnd
Moves focus to the first or last tag.
SpaceEnter
When selectable, toggles the focused tag's selection.
DeleteBackspace
Removes the focused tag, or every selected tag when the focused tag is selected.
Escape
Clears the selection.