Forms

Tag input

A list of tags with a text field on the end.

Client componentSource

Import

import { TagInput } from '@the_viveksingh/vivek-ui'

A list of tags

Enter or a delimiter commits a tag; Backspace in an empty box removes the last one. Each chip has its own labelled remove button, so a keyboard user is not stuck.

  • react
  • typescript
  • accessibility
3 tags: react, typescript, accessibility
<TagInput
  defaultValue={['react', 'typescript', 'accessibility']}
  placeholder="Add a topic"
  aria-label="Topics"
  onChange={setTopics}
/>

Validated

validate returns true, false, or a message shown to the user. Returning the reason is what turns a silent rejection into something fixable. Being a function, it also means the surrounding component has to be a Client Component.

  • vivek@example.com
1 tag: vivek@example.com

Type an address and press Enter or comma.

<Field label="Invite by email" help="Type an address and press Enter or comma.">
  <TagInput
    max={5}
    delimiters={[',', ' ']}
    addOnBlur
    validate={(tag) => (tag.includes('@') ? true : 'That is not an email address')}
    placeholder="name@company.com"
  />
</Field>

Props

Generated from the package's own type declarations, so this table cannot drift from the code.

Props for TagInput
PropTypeDefaultDescription
valuestring[]Controlled tags.
defaultValuestring[]Uncontrolled initial tags. Default `[]`.
onChange(value: string[]) => voidCalled with the whole new list on every add or remove, in both modes.
maxnumberHard cap. Further tags are rejected with reason `'max'`.
validate(tag: string, tags: string[]) => boolean | stringVet a candidate. Return `false` to reject silently, or a string to reject *and* show that message — which is the version worth using, because "nothing happened" is the least debuggable failure a form can offer.
allowDuplicatesbooleanPermit the same tag twice. Default `false`.
placeholderstring
size'sm' | 'md' | 'lg'
disabledboolean
readOnlyboolean
invalidbooleanSets `aria-invalid` on the text input. Injected by `Field`.
requiredbooleanInjected by `Field`. Marks the input required while there are no tags.
namestringSubmits one hidden input per tag, all under this name.
delimitersstring[]Extra characters that commit a tag. Default `[',']` — Enter always commits.
addOnBlurbooleanCommit whatever is typed when the field loses focus. Default `true`.
removeLabel(tag: string) => stringAccessible name for a tag's remove button. Default `` `Remove ${tag}` ``.
onReject(tag: string, reason: TagRejectReason) => voidTold about every refusal, with the reason.

Every remaining prop is spread onto the root element, so all standard HTML and ARIA attributes work. className and style are merged with the library's own, never replaced, and the ref forwards to the root DOM node.

Rendering