Components / inputs

Tag Input

A text field where each entry becomes a removable tag: type and press Enter or a separator, or paste a list.

import { TagInput } from '@basiiik/ui';

The snippet an agent gets

From get_component_snippet, with the required props filled in from the spec. Every snippet is type-checked against the library before it is shipped.

import { TagInput } from '@basiiik/ui';

<TagInput label="Invite teammates" />
  • Example values were filled in for the required prop label: replace them with your own.
  • Hover and Focused are CSS. Error is the error prop, or a rejected entry (the message validate returns). Disabled uses the disabled attribute. Filled is one or more entries, shown as tags. Needs label or aria-label.
  • Compose with: tag.
  • Storybook: Inputs/Tag Input.

Props

PropTypeNotes
size"sm" | "md"Default "md"
labelReactNode
helperTextReactNode
placeholdernative attribute
errorReactNode
disablednative attribute
aria-labelstring
aria-labelledbystring

Other props

PropTypeWhat it does
maxnumberThe most entries allowed.
valuesstring[]The entries (controlled), in the order they were added.
defaultValuesstring[]
onValuesChange(values: string[]) => void
separatorsstringCharacters that end an entry when typed or pasted. Default ",;\n". Add a space for things that never contain one, such as email addresses. Enter always ends an entry. In JSX pass an expression, separators={",; \n"}: inside a quoted attribute JSX does not unescape, so \n there would be a backslash and the letter n. A backslash-n or backslash-t written that way is read as a newline or a tab, so the mistake cannot turn every "n" into a separator.
validate(value: string) => boolean | stringChecks one entry. Return true to accept it, or false or a message to reject it: a rejected entry stays in the field with the message shown.
allowDuplicatesbooleanAllow the same entry twice. Default false: a repeat (ignoring case) is ignored with a message.
addOnBlurbooleanAdd what is typed when the field loses focus, so an entry is not lost when someone tabs away. Default true.
formatAdded(added: string[], count: number) => stringAnnounced when entries are added, for translation. Default: "ada@example.com added, 3 in total".
formatRemoved(value: string, count: number) => stringAnnounced when an entry is removed. Default: "ada@example.com removed, 2 in total".
formatRejected(value: string, reason: TagInputRejection, message?: string) => stringThe message for a rejected entry (also announced). message is the text validate returned, if any.
formatRemove(value: string) => stringAccessible name of an entry's remove control. Default: "Remove ada@example.com".
namestringName for a form: submits one value per entry.

States. Hover and Focused are CSS. Error is the error prop, or a rejected entry (the message validate returns). Disabled uses the disabled attribute. Filled is one or more entries, shown as tags. Needs label or aria-label.

Native attributes such as className, id and data-* are forwarded to the root element.

Use it when

  • Collect a list of free-text entries: email addresses to invite, keywords, skills, labels
  • Entries someone may paste in bulk
  • A list where each entry must pass a check (valid email, no spaces)

Do not use it when

  • The entries come from a fixed list (use Multi Combobox)
  • One value only (use Text Field)
  • A few known options (use Checkbox)
  • Long text or sentences (use Textarea)
  • Entries that need more than a name, such as a name and a role (use a Table of rows with a Text Field)

Rules for agents

  • The value is a list of strings: pass values (or defaultValues) and onValuesChange(values); the typed text is not part of the value until it is added
  • Needs a label or aria-label, like every field
  • For email addresses pass separators={",; \n"} as a JSX expression in braces (a space ends an entry too) and a validate that returns true, or a message to reject: (v) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(v) || 'Enter a valid email address'
  • Do not validate on your side after the fact: validate keeps the bad entry in the field with its message, so people can fix it
  • Set max when the count matters; set allowDuplicates only when a repeat is meaningful
  • Use name to submit one form field per entry
  • Say how to add in the helper text ("Press Enter or comma after each address, or paste a list"); the field does not show a hint of its own
  • Use error with a message when a required field has no entries (for example after a failed submit); required is met by one entry

Avoid

  • Hand-building tags with Tag next to a Text Field and your own add logic
  • Using it to pick from known options (use Multi Combobox)
  • A comma-separated string in a Text Field that you split on submit
  • A validate that silently drops the entry (return a message so people know why)
  • Space as a separator for entries that can contain spaces (names, skills)
  • Writing separators=",; \n" as a quoted JSX attribute: JSX does not unescape, so it is a backslash and the letter n (the component reads a backslash-n as a newline, but write it in braces)

Writing the content

  • Label: a plural noun or an action: "Invite teammates", "Skills"
  • Placeholder: an example of one entry: "name@example.com"
  • Helper text: how to add them, not what they are

Keyboard

  • Enter, comma or semicolon ends an entry (more separators with separators); Enter in an empty field is not swallowed, so a form can still submit
  • Backspace in an empty field removes the last tag
  • Escape clears the typed text; the tags stay
  • Each tag has a remove button in the tab order; Delete or Backspace on it removes the tag

Accessibility

  • A labelled text field; the tags are buttons named "Remove ada@example.com" (translate with formatRemove)
  • Every addition, removal and rejection is announced politely with the count (translate with formatAdded, formatRemoved, formatRejected)
  • A rejected entry sets aria-invalid and its message is the field's description

Colour tokens it reads

color.bg.disabledcolor.bg.subtlecolor.bg.surfacecolor.border.dangercolor.border.defaultcolor.border.focuscolor.border.inputcolor.border.subtlecolor.text.dangercolor.text.disabledcolor.text.primarycolor.text.secondarycolor.text.tertiary

Related

inputs 10 Figma variants Try it in the live demo