This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
TagsInput
A field that collects several short values as tags: type, press Enter (or the delimiter), and what you typed becomes a removable chip.
Given options, it is also a multi-select: the input becomes an APG combobox over a multiselectable listbox, filtered as you type, with DOM focus staying in the field and the active option tracked through aria-activedescendant. Typed text that matches no option is offered as a new tag, first in the list, so Enter adds what you typed; ↓ reaches the suggestions. create={false} limits it to the list. The tags themselves are one tab stop with the input: ← at the start of the field, or Backspace in an empty one, moves focus onto the last tag's remove button, and ←/→ walk between them. Backspace there removes it — two presses, so a stray Backspace never deletes a tag.
Forms · two-way: bind:values · submits in a form with name · portalled to <body> · keyboard contract
<script lang="ts">
import { TagsInput } from '@l4st/driftwood';
</script>
| Light | Dark |
|---|---|
![]() |
![]() |
Props
| Prop | Type | Default | What it does |
|---|---|---|---|
values bind: |
string[] |
[] |
The tags, in the order they were added. |
options |
TagsInputOption[] |
— | Suggestions. Given these, the field opens a list and works as a multi-select. |
create |
boolean |
true |
Accept values that are not in options. Without options this is the only way in. |
delimiter |
string |
',' |
A key that adds the typed text like Enter does. Pasted text is split on it too. '' turns it off. |
max |
number |
— | At most this many tags. Adding stops there; removing still works. |
addOnBlur |
boolean |
false |
Add the typed text when focus leaves the field, instead of dropping it. |
placeholder |
string |
'Add…' |
Shown while there are no tags and nothing typed. |
disabled |
boolean |
false |
Blocks typing and removing. |
name |
string |
— | Submits one field per tag, like a multiple <select>. |
id |
string |
— | Points a <Label for=…> at the input. |
class |
string |
— | Merged with the component's own classes, last — so yours win. |
aria-label |
string |
— | Accessible name, when no visible <Label for=…> points at this. |
aria-labelledby |
string |
— | Id of the element that names this, instead of aria-label. |
filter |
(option: TagsInputOption, query: string) => boolean |
(option, query) => option.label.toLowerCase().includes(query.toLowerCase()) |
Match an option against what was typed. Default: case-insensitive substring. |
emptyLabel |
string |
'No matches' |
Shown when the filter matches nothing and nothing can be created. Localise here. |
createLabel |
(text: string) => string |
(text: string) => `Add "${text}"` |
The list item that adds typed text as a new tag. Localise here. |
removeLabel |
(label: string) => string |
(label: string) => `Remove ${label}` |
Accessible name of a tag's × button. Localise here. |
announce |
(label: string, change: 'added' | 'removed') => string |
(label: string, change: 'added' | 'removed') => `${label} ${change}` |
What a screen reader hears when a tag comes or goes. Localise here. |
onValuesChange |
(values: string[]) => void |
— | Every change to the tags. |
onCreate |
(value: string) => void |
— | A tag that is not one of options was added — every tag, without options. |
Everything not listed above is spread onto the underlying element (HTMLInputAttributes): aria-*, data-*, event handlers, and the rest of the native attributes.
Types
export type TagsInputOption = {
value: string;
label: string;
disabled?: boolean;
};
Keyboard
| Key | Does |
|---|---|
| Enter / , | add the typed text as a tag — with options, toggle the active one |
| ↑ / ↓ | move the active option, when there are options |
| Home / End | first / last option, while the list is open |
| ← / Backspace | from the start of the field, move onto the last tag |
| ← / → | move between tags; → past the last returns to the field |
| Backspace / Delete | remove the focused tag |
| Escape | close the list, then clear the typed text |
Example
The markup behind the screenshot above, lifted from src/routes/shots/ — so it
compiles, and it is exactly what produced the image.
<TagsInput
options={[
{ value: 'media', label: 'media' },
{ value: 'backups', label: 'backups' },
{ value: 'code', label: 'code' }
]}
values={['media', 'backups', 'nightly']}
placeholder="Add a tag"
aria-label="Tags"
/>
Forms · Field · Input · FileInput · FileList · Textarea · CodeEditor · Combobox · RadioGroup · NumberInput · InlineEdit · Label · Select · MultiSelect · DatePicker · Checkbox · Switch · Slider
driftwood
Layout
Actions
Forms
- Field
- Input
- FileInput
- FileList
- Textarea
- CodeEditor
- Combobox
- RadioGroup
- NumberInput
- InlineEdit
- Label
- Select
- MultiSelect
- DatePicker
- TagsInput
- Checkbox
- Switch
- Slider
Feedback
Charts
Overlays
Navigation
Generated from the source by pnpm wiki · repository · v0.24.0

