Tags Input
Used to enter multiple values as tags with features like tag creation, deletion, and keyboard navigation.
'use client'
import { Span, TagsInput } from '@chakra-ui/react'
export const TagsInputBasic = () => {
return (
<TagsInput.Root defaultValue={['React', 'Saas UI', 'TypeScript']}>
<TagsInput.Label>Tags</TagsInput.Label>
<TagsInput.Control>
<TagsInput.Items />
<TagsInput.Input placeholder="Add tag..." />
</TagsInput.Control>
<Span textStyle="xs" color="fg.muted" ms="auto">
Press Enter or Return to add tag
</Span>
</TagsInput.Root>
)
}
Anatomy
import { TagsInput } from '@chakra-ui/react'<TagsInput.Root>
<TagsInput.Label />
<TagsInput.Control>
<TagsInput.Item>
<TagsInput.ItemPreview>
<TagsInput.ItemText />
<TagsInput.ItemDeleteTrigger />
</TagsInput.ItemPreview>
<TagsInput.ItemInput />
</TagsInput.Item>
<TagsInput.Input />
</TagsInput.Control>
</TagsInput.Root>If you don't need to customize the individual tags, use the TagsInput.Items
shortcut. It renders all tag items automatically based on the current value.
<TagsInput.Root>
<TagsInput.Label />
<TagsInput.Control>
<TagsInput.Items />
<TagsInput.Input />
</TagsInput.Control>
</TagsInput.Root>Examples
Basic
Tags are created when the user presses Enter or Return, and removed with
Backspace or the delete trigger on each tag.
'use client'
import { Span, TagsInput } from '@chakra-ui/react'
export const TagsInputBasic = () => {
return (
<TagsInput.Root defaultValue={['React', 'Saas UI', 'TypeScript']}>
<TagsInput.Label>Tags</TagsInput.Label>
<TagsInput.Control>
<TagsInput.Items />
<TagsInput.Input placeholder="Add tag..." />
</TagsInput.Control>
<Span textStyle="xs" color="fg.muted" ms="auto">
Press Enter or Return to add tag
</Span>
</TagsInput.Root>
)
}
Sizes
Use the size prop to adjust the size of the tags input.
'use client'
import { For, Stack, TagsInput } from '@chakra-ui/react'
export const TagsInputWithSizes = () => {
return (
<Stack gap="6">
<For each={['xs', 'sm', 'md', 'lg'] as const}>
{(size) => (
<TagsInput.Root
key={size}
size={size}
readOnly
defaultValue={['React', 'Saas UI', 'TypeScript']}
>
<TagsInput.Label>Tags (size={size})</TagsInput.Label>
<TagsInput.Control>
<TagsInput.Items />
<TagsInput.Input placeholder="Add tag..." />
</TagsInput.Control>
</TagsInput.Root>
)}
</For>
</Stack>
)
}
Variants
Use the variant prop to change the visual style of the tags input.
'use client'
import { For, Stack, TagsInput } from '@chakra-ui/react'
export const TagsInputWithVariants = () => {
return (
<Stack gap="6">
<For each={['outline', 'subtle', 'flushed'] as const}>
{(variant) => (
<TagsInput.Root
key={variant}
variant={variant}
readOnly
defaultValue={['React', 'Saas UI', 'TypeScript']}
>
<TagsInput.Label>Tags (variant={variant})</TagsInput.Label>
<TagsInput.Control>
<TagsInput.Items />
<TagsInput.Input placeholder="Add tag..." />
</TagsInput.Control>
</TagsInput.Root>
)}
</For>
</Stack>
)
}
Controlled
Use the value and onValueChange props to programmatically control the tags.
'use client'
import { useState } from 'react'
import { TagsInput } from '@chakra-ui/react'
export const TagsInputControlled = () => {
const [tags, setTags] = useState<string[]>(['React', 'Saas UI'])
return (
<TagsInput.Root
value={tags}
onValueChange={(details) => setTags(details.value)}
>
<TagsInput.Label>Tags</TagsInput.Label>
<TagsInput.Control>
<TagsInput.Items />
<TagsInput.Input placeholder="Add tag..." />
</TagsInput.Control>
</TagsInput.Root>
)
}
Max Tags
Pass the max prop to the TagsInput.Root component to limit the number of
tags that can be added. Combine it with the validate prop to only accept tags
that pass your own validation rules.
'use client'
import { Badge, Button, HStack, Span, TagsInput } from '@chakra-ui/react'
const EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
const isValidEmail = (value: string) => EMAIL_REGEX.test(value)
export const TagsInputWithMax = () => {
return (
<TagsInput.Root
max={3}
validate={(e) => isValidEmail(e.inputValue)}
defaultValue={['sage@company.com']}
>
<TagsInput.Label>Invite guests (max 3)</TagsInput.Label>
<TagsInput.Control>
<TagsInput.Items />
<TagsInput.Input placeholder="Add guests" />
</TagsInput.Control>
<TagsInput.Context>
{({ value }) => (
<HStack justify="space-between" hidden={value.length === 0} mt="2.5">
<Span textStyle="sm">
You've invited <Badge>{value.length} / 3 guests</Badge> to
your event
</Span>
<Button size="sm">Invite</Button>
</HStack>
)}
</TagsInput.Context>
</TagsInput.Root>
)
}
Editable Tags
Use the editable prop to enable inline editing of existing tags by double
clicking or pressing Enter when highlighted, allowing users to quickly update
tag values.
'use client'
import { Span, TagsInput } from '@chakra-ui/react'
export const TagsInputEditable = () => {
return (
<TagsInput.Root editable defaultValue={['React', 'Saas UI']}>
<TagsInput.Label>Edit tags inline</TagsInput.Label>
<TagsInput.Control>
<TagsInput.Items />
<TagsInput.Input placeholder="Add or edit tags..." />
<TagsInput.ClearTrigger />
</TagsInput.Control>
<TagsInput.HiddenInput />
<Span textStyle="xs" color="fg.muted" ms="auto">
Use the arrow keys to navigate and press Enter to edit
</Span>
</TagsInput.Root>
)
}
Field
Compose the TagsInput component with the Field component to add helper text
and error messages. This example also uses the delimiter and addOnPaste
props so users can paste a comma separated list of emails.
'use client'
import { Field, TagsInput } from '@chakra-ui/react'
export const TagsInputWithField = () => {
return (
<Field.Root>
<TagsInput.Root
delimiter=","
addOnPaste
defaultValue={['sage@company.com']}
>
<TagsInput.Label>Invite team members</TagsInput.Label>
<TagsInput.Control>
<TagsInput.Items />
<TagsInput.Input placeholder="Add email..." />
</TagsInput.Control>
</TagsInput.Root>
<Field.HelperText>Add emails separated by commas</Field.HelperText>
</Field.Root>
)
}
Props
Root
| Prop | Default | Type |
|---|---|---|
addOnPaste | false | booleanWhether to add a tag when you paste values into the tag input |
allowDuplicates | false | booleanWhether to allow duplicate tags. |
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 |
editable | true | booleanWhether a tag can be edited after creation, by pressing `Enter` or double clicking. |
max | 'Infinity' | numberThe max number of tags |
sanitizeValue | '(value) => value.trim()' | (value: string) => stringFunction to sanitize the tag value before adding. Useful for trimming whitespace, normalizing case, or stripping special characters. |
colorPalette | 'gray' | 'base' | 'gray' | 'zinc' | 'neutral' | 'stone' | 'red' | 'orange' | 'amber' | 'yellow' | 'lime' | 'green' | 'emerald' | 'teal' | 'cyan' | 'sky' | 'blue' | 'indigo' | 'violet' | 'purple' | 'fuchsia' | 'pink' | 'rose' | 'sidebar' | 'sidebar.accent' | 'interaction' | 'accent' | 'presence' | 'status' | 'slate'The color palette of the component |
size | 'md' | 'xs' | 'sm' | 'md' | 'lg'The size of the component |
variant | 'outline' | 'outline' | 'subtle' | 'flushed'The variant of the component |
allowOverflow | booleanWhether to allow tags to exceed max. In this case, we'll attach `data-invalid` to the root | |
asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. | |
autoFocus | booleanWhether the input should be auto-focused | |
blurBehavior | 'clear' | 'add'The behavior of the tags input when the input is blurred - `"add"`: add the input value as a new tag - `"clear"`: clear the input value | |
defaultInputValue | stringThe initial tag input value when rendered. Use when you don't need to control the tag input value. | |
defaultValue | string[]The initial tag value when rendered. Use when you don't need to control the tag value. | |
disabled | booleanWhether the tags input should be disabled | |
form | stringThe associate form of the underlying input element. | |
id | stringThe unique identifier of the machine. | |
ids | Partial<{
root: string
input: string
hiddenInput: 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 controlled tag input's value | |
invalid | booleanWhether the tags input is invalid | |
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` | |
placeholder | stringThe placeholder text for the input | |
readOnly | booleanWhether the tags input should be read-only | |
required | booleanWhether the tags input is required | |
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 controlled tag value |
Item
| Prop | Default | Type |
|---|---|---|
index * | string | number | |
value * | string | |
asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. | |
disabled | boolean |