Tag Input

Free-text chips for keywords, recipients or labels. Backspace on an empty field removes the last tag, and pasting a comma-separated list splits it rather than making one long tag.

src/components/ui/tag-input.tsx

About

From the component's own source, where it was written.

Free-text chips: keywords, recipients, labels.

Backspace on an empty field removes the last tag, which is the behaviour everyone expects from every mail client. It removes rather than "selects then removes" — the two-step version is more careful and nobody discovers it.

Pasting splits on the delimiters too, so pasting a comma-separated list gives a list of tags rather than one tag with commas in it.

Each chip's remove button is a real tab stop. A chip you can only delete by pointer is unremovable from the keyboard once you have tabbed past the field.

Install

npx astralyx-ui add tag-input

Usage

import { TagInput } from '@/components/ui/tag-input'

<TagInput value={tags} onValueChange={setTags} max={8} />

Composer

Change the props and the source below follows.

reacttailwind
Props
tsx
<TagInput
  defaultValue={['react', 'tailwind']}
  max={6}
  allowDuplicates={false}
/>

Examples

Tags

API

Generated from the source, so it cannot fall behind the code. One table per exported component, then hooks, functions and types.

TagInput

Free-text chips: keywords, recipients, labels.

Extends Omit<ComponentProps<'div'>, 'defaultValue' | 'onChange'>.

PropTypeDefaultDescription
valuestring[]—Controlled or uncontrolled.
defaultValuestring[][]Controlled or uncontrolled.
onValueChange(tags: string[]) => void—Controlled or uncontrolled.
placeholderstring'Add and press Enter'—
delimitersstring[][',', 'Enter', 'Tab']Keys and characters that commit the current text. Tab only commits when there is something to commit, so an empty field still moves focus.
maxnumber—At the limit the field is disabled and says so.
allowDuplicatesbooleanfalseAt the limit the field is disabled and says so.
sizekeyof typeof fieldSize'md'—
variant'default' | 'secondary' | 'ghost''default'—
errorbooleanfalse—
disabledbooleanfalse—
validate(tag: string) => boolean—Reject an entry — an email shape, a length bound.

Behaviour

TopicDetailDescription
removalkeyboard + pointerEach chip has a real tab-stop remove button; a chip removable only by pointer is unreachable once you tab past the field.