Tags Input
Create, navigate, and remove free-form tokens from one text field.
Usage
Skills
Create and remove free-form skill tags without losing input focus.
Create and remove free-form skill tags without losing input focus.
Press Enter or comma to add a tag.
<!-- Tags Input / Skills -->
<script setup lang="ts">
import { TagsInputRoot, TagsInputItem, TagsInputItemText, TagsInputItemDelete, TagsInputInput, TagsInputClear } from '@sectile/vue/tags-input'
import { Trash2, X } from '@lucide/vue'
</script>
<template>
<TagsInputRoot :default-value="['Vue', 'DOM', 'Accessibility']" label="Project skills" v-slot="{ value }">
<TagsInputItem v-for="(_, index) in value" :key="index" :index="index">
<TagsInputItemText />
<TagsInputItemDelete :aria-label="`Remove ${value[index]}`">
<X aria-hidden="true" />
</TagsInputItemDelete>
</TagsInputItem>
<TagsInputInput placeholder="Add a skill…" />
<TagsInputClear><Trash2 aria-hidden="true" /> Clear all</TagsInputClear>
</TagsInputRoot>
</template>Limited
Enforce the configured item or visible-notification limit without losing existing values.
Enforce the configured item or visible-notification limit without losing existing values.
Press Enter or comma to add a tag.
<!-- Tags Input / Limited -->
<script setup lang="ts">
import { TagsInputRoot, TagsInputItem, TagsInputItemText, TagsInputItemDelete, TagsInputInput, TagsInputClear } from '@sectile/vue/tags-input'
import { Trash2, X } from '@lucide/vue'
</script>
<template>
<TagsInputRoot :default-value="['Vue', 'DOM', 'Accessibility']" label="Project skills" v-slot="{ value }">
<TagsInputItem v-for="(_, index) in value" :key="index" :index="index">
<TagsInputItemText />
<TagsInputItemDelete :aria-label="`Remove ${value[index]}`">
<X aria-hidden="true" />
</TagsInputItemDelete>
</TagsInputItem>
<TagsInputInput placeholder="Add a skill…" />
<TagsInputClear><Trash2 aria-hidden="true" /> Clear all</TagsInputClear>
</TagsInputRoot>
</template>Controlled
Let the parent own the current value and apply accepted changes back to the component.
Let the parent own the current value and apply accepted changes back to the component.
Press Enter or comma to add a tag.
<!-- Tags Input / Controlled -->
<script setup lang="ts">
import { TagsInputRoot, TagsInputItem, TagsInputItemText, TagsInputItemDelete, TagsInputInput, TagsInputClear } from '@sectile/vue/tags-input'
import { Trash2, X } from '@lucide/vue'
</script>
<template>
<TagsInputRoot :default-value="['Vue', 'DOM', 'Accessibility']" label="Project skills" v-slot="{ value }">
<TagsInputItem v-for="(_, index) in value" :key="index" :index="index">
<TagsInputItemText />
<TagsInputItemDelete :aria-label="`Remove ${value[index]}`">
<X aria-hidden="true" />
</TagsInputItemDelete>
</TagsInputItem>
<TagsInputInput placeholder="Add a skill…" />
<TagsInputClear><Trash2 aria-hidden="true" /> Clear all</TagsInputClear>
</TagsInputRoot>
</template>API
Vue package: @sectile/vue/tags-input
TagsInputRootTagsInputItemTagsInputItemTextTagsInputItemDeleteTagsInputInputTagsInputClear
Props
TagsInputRootProps
as- Type
PrimitiveAsDefault'div'Element or component rendered for this part.
asChild- Type
booleanDefaultfalseWhether to merge this part into its single child instead of rendering a wrapper.
defaultInputValue- Type
stringDefault''Initial uncontrolled text shown by the editable input.
defaultValue- Type
readonly string[]Default[]Initial value used when the component owns its state.
disabled- Type
booleanDefaultfalseWhether interaction is unavailable.
form- Type
stringDefaultundefinedID of the native form associated with the control.
inputValue- Type
stringDefaultundefinedControlled text currently shown by the editable input.
label- Type
stringDefault'Tags'Accessible name announced for the control.
modelValue- Type
readonly string[]DefaultundefinedCurrent value when state is controlled by the parent.
name- Type
stringDefaultundefinedName used for native form submission.
policies- Type
TagsInputPoliciesDefaultundefinedBehavior policies that customize validation, movement, or selection.
readonly- Type
booleanDefaultfalseWhether the value can be inspected but not changed.
required- Type
booleanDefaultfalseWhether the control must contain a valid value before submission.
TagsInputItemProps
as- Type
PrimitiveAsDefaultundefinedElement or component rendered for this part.
asChild- Type
booleanDefaultundefinedWhether to merge this part into its single child instead of rendering a wrapper.
index- Type
numberDefaultRequiredZero-based position of this part in its parent collection.
TagsInputPartProps
as- Type
PrimitiveAsDefaultVaries by partElement or component rendered for this part.
asChild- Type
booleanDefaultfalseWhether to merge this part into its single child instead of rendering a wrapper.
Slots
TagsInputRootSlotProps
disabled- Type
booleanWhether interaction is unavailable.
inputValue- Type
stringCurrent editable input text.
readonly- Type
booleanWhether the value can be inspected but not changed.
value- Type
readonly string[]Current value exposed by this contract.
TagsInputItemSlotProps
disabled- Type
booleanWhether interaction is unavailable.
index- Type
numberZero-based position in the parent collection.
readonly- Type
booleanWhether the value can be inspected but not changed.
value- Type
stringCurrent value exposed by this contract.
Events
TagsInputRoot
update:inputValue- Payload
stringEmitted when editable input text changes.
update:modelValue- Payload
readonly string[]Emitted when the component requests a new controlled value.
Other types
TagsInputValueChangeHandler
type TagsInputValueChangeHandler = (value: readonly string[]) => voidTagsInputInputValueChangeHandler
type TagsInputInputValueChangeHandler = (value: string) => voidParts
Shared scope: [data-scope="tags-input"]. Combine it with a part selector to keep styles local to this component.
| Part | Selector | Role | Extra attributes |
|---|---|---|---|
root | [data-part="root"] | Defines the component boundary and owns its composed parts. | — |
item | [data-part="item"] | Represents one selectable or actionable item. | — |
item-text | [data-part="item-text"] | Renders the item label independently from its controls. | — |
item-delete | [data-part="item-delete"] | Removes its owning item. | — |
input | [data-part="input"] | Accepts the editable value or draft. | — |
clear | [data-part="clear"] | Clears the current value or collection. | — |
Keyboard interaction
| Key | Behavior |
|---|---|
| Enter / Comma | Commit the current input as a tag. |
| Arrow Left / Arrow Right | Move between the input and existing tags. |
| Backspace / Delete | Move to or remove the current tag according to cursor state. |
Accessibility
The labeled group keeps its text input native and names every removable tag action.
