Tags Input
A component that allows users to add tags to an input field.
Anatomy
To set up the tags input correctly, you'll need to understand its anatomy and how we name its parts.
Each part includes a
data-partattribute to help identify them in the DOM.
Examples
Learn how to use the TagsInput component in your project. Let's take a look at
the most basic example:
import { TagsInput } from '@ark-ui/react'
export const Basic = () => {
return (
<TagsInput.Root>
<TagsInput.Context>
{(tagsInput) => (
<>
<TagsInput.Label>Frameworks</TagsInput.Label>
<TagsInput.Control>
{tagsInput.value.map((value, index) => (
<TagsInput.Item key={index} index={index} value={value}>
<TagsInput.ItemPreview>
<TagsInput.ItemText>{value}</TagsInput.ItemText>
<TagsInput.ItemDeleteTrigger>Delete</TagsInput.ItemDeleteTrigger>
</TagsInput.ItemPreview>
<TagsInput.ItemInput />
</TagsInput.Item>
))}
</TagsInput.Control>
<TagsInput.Input placeholder="Add Framework" />
<TagsInput.ClearTrigger>Clear all</TagsInput.ClearTrigger>
</>
)}
</TagsInput.Context>
<TagsInput.HiddenInput />
</TagsInput.Root>
)
}
import { Index } from 'solid-js'
import { TagsInput } from '@ark-ui/solid'
export const Basic = () => (
<TagsInput.Root>
<TagsInput.Context>
{(api) => (
<>
<TagsInput.Label>Frameworks</TagsInput.Label>
<TagsInput.Control>
<Index each={api().value}>
{(value, index) => (
<TagsInput.Item index={index} value={value()}>
<TagsInput.ItemPreview>
<TagsInput.ItemText>{value()}</TagsInput.ItemText>
<TagsInput.ItemDeleteTrigger>Delete</TagsInput.ItemDeleteTrigger>
</TagsInput.ItemPreview>
<TagsInput.ItemInput />
</TagsInput.Item>
)}
</Index>
<TagsInput.Input placeholder="Add Framework" />
<TagsInput.ClearTrigger>Clear All</TagsInput.ClearTrigger>
</TagsInput.Control>
</>
)}
</TagsInput.Context>
<TagsInput.HiddenInput />
</TagsInput.Root>
)
<script setup lang="ts">
import { TagsInput } from '@ark-ui/vue'
</script>
<template>
<TagsInput.Root>
<TagsInput.Context v-slot="tagsInput">
<TagsInput.Label>Frameworks</TagsInput.Label>
<TagsInput.Control>
<TagsInput.Item
v-for="(value, index) in tagsInput.value"
:key="index"
:index="index"
:value="value"
>
<TagsInput.ItemPreview>
<TagsInput.ItemText>{{ value }}</TagsInput.ItemText>
<TagsInput.ItemDeleteTrigger>Delete</TagsInput.ItemDeleteTrigger>
</TagsInput.ItemPreview>
<TagsInput.ItemInput />
</TagsInput.Item>
<TagsInput.Input placeholder="Add Framework" />
<TagsInput.ClearTrigger>Clear all</TagsInput.ClearTrigger>
</TagsInput.Control>
</TagsInput.Context>
<TagsInput.HiddenInput />
</TagsInput.Root>
</template>
Navigating and Editing tags
When the input has an empty value or the caret is at the start position, the tags can be selected by using the arrow left and arrow right keys. When "visual" focus in on any tag:
- Pressing Enter or double-clicking on the tag will put it in edit mode, allowing the user change its value and press Enter to commit the changes.
- Pressing Delete or Backspace will delete the tag that has visual focus.
Setting the initial tags
To set the initial tag values, set the defaultValue prop.
Example not foundExample not foundExample not foundLimiting the number of tags
To limit the number of tags within the component, you can set the max property
to the limit you want. The default value is Infinity.
When the tag reaches the limit, new tags cannot be added except the
allowOverflow prop is set to true.
Example not foundExample not foundExample not foundValidating Tags
Before a tag is added, the validate function is called to determine whether to
accept or reject a tag.
A common use-case for validating tags is preventing duplicates or validating the data type.
import { TagsInput } from '@ark-ui/react'
export const Validated = () => {
return (
<TagsInput.Root
validate={(details) => {
return !details.value.includes(details.inputValue)
}}
>
<TagsInput.Context>
{(tagsInput) => (
<>
<TagsInput.Label>Frameworks</TagsInput.Label>
<TagsInput.Control>
{tagsInput.value.map((value, index) => (
<TagsInput.Item key={index} index={index} value={value}>
<TagsInput.ItemInput />
<TagsInput.ItemText>{value}</TagsInput.ItemText>
<TagsInput.ItemDeleteTrigger>Delete</TagsInput.ItemDeleteTrigger>
</TagsInput.Item>
))}
</TagsInput.Control>
<TagsInput.Input placeholder="Add Framework" />
<TagsInput.ClearTrigger>Clear all</TagsInput.ClearTrigger>
</>
)}
</TagsInput.Context>
<TagsInput.HiddenInput />
</TagsInput.Root>
)
}
import { Index } from 'solid-js'
import { TagsInput } from '@ark-ui/solid'
export const Validated = () => {
return (
<TagsInput.Root
validate={(details) => {
return !details.value.includes(details.inputValue)
}}
>
<TagsInput.Context>
{(api) => (
<>
<TagsInput.Label>Frameworks</TagsInput.Label>
<TagsInput.Control>
<Index each={api().value}>
{(value, index) => (
<TagsInput.Item index={index} value={value()}>
<TagsInput.ItemText>{value()}</TagsInput.ItemText>
<TagsInput.ItemInput />
<TagsInput.ItemDeleteTrigger>Delete</TagsInput.ItemDeleteTrigger>
</TagsInput.Item>
)}
</Index>
</TagsInput.Control>
<TagsInput.Input placeholder="Add Framework" />
<TagsInput.ClearTrigger>Clear all</TagsInput.ClearTrigger>
</>
)}
</TagsInput.Context>
<TagsInput.HiddenInput />
</TagsInput.Root>
)
}
<script setup lang="ts">
import { TagsInput } from '@ark-ui/vue'
</script>
<template>
<TagsInput.Root
:validate="
(details) => {
return !details.value.includes(details.inputValue)
}
"
>
<TagsInput.Context v-slot="tagsInput">
<TagsInput.Label>Frameworks</TagsInput.Label>
<TagsInput.Control>
<TagsInput.Item
v-for="(value, index) in tagsInput.value"
:key="index"
:index="index"
:value="value"
>
<TagsInput.ItemInput />
<TagsInput.ItemText>{{ value }}</TagsInput.ItemText>
<TagsInput.ItemDeleteTrigger>Delete</TagsInput.ItemDeleteTrigger>
</TagsInput.Item>
<TagsInput.Input placeholder="Add Framework" />
<TagsInput.ClearTrigger>Clear all</TagsInput.ClearTrigger>
</TagsInput.Control>
</TagsInput.Context>
<TagsInput.HiddenInput />
</TagsInput.Root>
</template>
Blur behavior
When the tags input is blurred, you can configure the action the component
should take by passing the blurBehavior prop.
add— Adds the tag to the list of tags.clear— Clears the tags input value.
Example not foundExample not foundExample not foundPaste behavior
To add a tag when a arbitrary value is pasted in the input element, pass the
addOnPaste prop.
When a value is pasted, the component will:
- check if the value is a valid tag based on the
validateoption - split the value by the
delimiteroption passed
Example not foundExample not foundExample not foundDisable tag editing
by default the tags can be edited by double-clicking on the tag or focusing on
them and pressing Enter. To disable this behavior, pass
allowEditTag={false}
Example not foundExample not foundExample not foundEvents
During the lifetime of the tags input interaction, here's a list of events we emit:
onValueChange— invoked when the tag value changes.onHighlightChange— invoked when a tag has visual focus.onValueInvalid— invoked when the max tag count is reached or thevalidatefunction returnsfalse.
Example not foundExample not foundExample not foundAPI Reference
Root
| Prop | Default | Type |
|---|---|---|
addOnPaste | booleanWhether to add a tag when you paste values into the tag input | |
allowOverflow | booleanWhether to allow tags to exceed max. In this case, we'll attach `data-invalid` to the root | |
asChild | booleanRender as a different element type. | |
autoFocus | booleanWhether the input should be auto-focused | |
blurBehavior | 'none' | 'clear' | 'add'The behavior of the tags input when the input is blurred - `"add"`: add the input value as a new tag - `"none"`: do nothing - `"clear"`: clear the input value |
defaultValue | string[]The initial value of the tags input when it is first rendered. Use when you do not need to control the state of the tags input. | |
delimiter | ',' | string | RegExpThe character that serves has: - event key to trigger the addition of a new tag - character used to split tags when pasting into the input |
disabled | booleanWhether the tags input should be disabled | |
editable | booleanWhether a tag can be edited after creation. If `true` and focus is on a tag, pressing `Enter`or double clicking will edit the tag. | |
form | stringThe associate form of the underlying input element. | |
id | stringThe unique identifier of the machine. | |
ids | Partial<{
root: string
input: string
clearBtn: string
label: string
control: string
item(opts: ItemProps): string
itemDeleteTrigger(opts: ItemProps): string
itemInput(opts: ItemProps): string
}>The ids of the elements in the tags input. Useful for composition. | |
inputValue | stringThe tag input's value | |
invalid | booleanWhether the tags input is invalid | |
max | numberThe max number of tags | |
maxLength | numberThe max length of the input. | |
name | stringThe name attribute for the input. Useful for form submissions | |
onFocusOutside | (event: FocusOutsideEvent) => voidFunction called when the focus is moved outside the component | |
onHighlightChange | (details: HighlightChangeDetails) => voidCallback fired when a tag is highlighted by pointer or keyboard navigation | |
onInputValueChange | (details: InputValueChangeDetails) => voidCallback fired when the input value is updated | |
onInteractOutside | (event: InteractOutsideEvent) => voidFunction called when an interaction happens outside the component | |
onPointerDownOutside | (event: PointerDownOutsideEvent) => voidFunction called when the pointer is pressed down outside the component | |
onValueChange | (details: ValueChangeDetails) => voidCallback fired when the tag values is updated | |
onValueInvalid | (details: ValidityChangeDetails) => voidCallback fired when the max tag count is reached or the `validateTag` function returns `false` | |
readOnly | booleanWhether the tags input should be read-only | |
translations | IntlTranslationsSpecifies the localized strings that identifies the accessibility elements and their states | |
validate | (details: ValidateArgs) => booleanReturns a boolean that determines whether a tag can be added. Useful for preventing duplicates or invalid tag values. | |
value | string[]The tag values |
ClearTrigger
| Prop | Default | Type |
|---|---|---|
asChild | booleanRender as a different element type. |
Control
| Prop | Default | Type |
|---|---|---|
asChild | booleanRender as a different element type. |
HiddenInput
| Prop | Default | Type |
|---|---|---|
asChild | booleanRender as a different element type. |
Input
| Prop | Default | Type |
|---|---|---|
asChild | booleanRender as a different element type. |
ItemDeleteTrigger
| Prop | Default | Type |
|---|---|---|
asChild | booleanRender as a different element type. |
ItemInput
| Prop | Default | Type |
|---|---|---|
asChild | booleanRender as a different element type. |
ItemPreview
| Prop | Default | Type |
|---|---|---|
asChild | booleanRender as a different element type. |
Item
| Prop | Default | Type |
|---|---|---|
index | string | number | |
value | string | |
asChild | booleanRender as a different element type. | |
disabled | boolean |
ItemText
| Prop | Default | Type |
|---|---|---|
asChild | booleanRender as a different element type. |
Label
| Prop | Default | Type |
|---|---|---|
asChild | booleanRender as a different element type. |