Tag Group
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.
$ npm add reka-uiAnatomy
Import all parts and piece them together.
<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 Attribute | Value |
|---|---|
[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 Attribute | Value |
|---|---|
[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 Attribute | Value |
|---|---|
[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.
<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.
<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.
<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.
<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
| Key | Description |
|---|---|
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. |
