Skip to main content

Usage

import { TagsInput } from '@kivora/react';

function Demo() {
  const [tags, setTags] = useState<string[]>([]);
  
  return (
    <TagsInput 
      label="Topics" 
      value={tags}
      onChange={setTags}
      placeholder="Add topic..."
    />
  );
}

Props

value
string[]
Controlled array of tag strings.
defaultValue
string[]
default:"[]"
Default tags for uncontrolled mode.
onChange
(tags: string[]) => void
Called when tags change. Receives the updated array of tags.
label
string
Label text displayed above the input.
placeholder
string
default:"'Add tag…'"
Placeholder text shown when no tags exist.
error
string
Error message to display below the input.
disabled
boolean
default:"false"
Disables the input and prevents tag management.
maxTags
number
Maximum number of tags allowed.
allowDuplicates
boolean
default:"false"
Allow duplicate tags. When false, adding an existing tag is ignored.
splitChars
string[]
default:"['Enter', ',']"
Characters/keys that trigger tag creation.
size
'sm' | 'md'
default:"'md'"
Size variant affecting input and tag sizing.
className
string
default:"''"
Additional CSS classes to apply to the container.
id
string
HTML ID attribute. Auto-generated if not provided.

Examples

Basic Tags Input

<TagsInput 
  label="Skills" 
  placeholder="Add skill..."
/>

Controlled Tags

function ControlledDemo() {
  const [tags, setTags] = useState<string[]>(['React', 'TypeScript']);
  
  return (
    <TagsInput
      label="Technologies"
      value={tags}
      onChange={setTags}
      placeholder="Add technology..."
    />
  );
}

With Max Tags

<TagsInput
  label="Top 3 Skills"
  maxTags={3}
  placeholder="Add up to 3 skills..."
/>

Allow Duplicates

<TagsInput
  label="Keywords"
  allowDuplicates
  placeholder="Add keyword..."
/>

Custom Split Characters

<TagsInput
  label="Email addresses"
  splitChars={['Enter', ',', ';', ' ']}
  placeholder="Add email..."
/>

Different Sizes

<TagsInput label="Small" size="sm" />
<TagsInput label="Medium" size="md" />

With Error State

function ValidatedTags() {
  const [tags, setTags] = useState<string[]>([]);
  
  return (
    <TagsInput
      label="Categories"
      value={tags}
      onChange={setTags}
      error={tags.length === 0 ? 'At least one tag required' : undefined}
    />
  );
}

Blog Post Tags Example

function BlogTagsInput() {
  const [tags, setTags] = useState<string[]>([]);
  const maxTags = 5;
  
  return (
    <div>
      <TagsInput
        label="Post Tags"
        value={tags}
        onChange={setTags}
        maxTags={maxTags}
        placeholder="Add tag and press Enter..."
        error={tags.length > maxTags ? `Maximum ${maxTags} tags allowed` : undefined}
      />
      <p className="text-xs text-muted-foreground mt-1">
        {tags.length}/{maxTags} tags
      </p>
    </div>
  );
}

Email Recipients

function EmailInput() {
  const [recipients, setRecipients] = useState<string[]>([]);
  
  const validateEmail = (email: string) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
  
  return (
    <TagsInput
      label="To"
      value={recipients}
      onChange={setRecipients}
      splitChars={['Enter', ',', ';', ' ']}
      placeholder="Enter email addresses..."
    />
  );
}

Keyboard Behavior

  • Enter: Create tag from current input
  • Comma (,): Create tag from current input (default)
  • Backspace: Remove last tag if input is empty
  • Blur: Create tag from current input if not empty

Notes

  • Tags display as removable chips with × button
  • Type text and press Enter or comma to add tag
  • Click × on tag to remove it
  • Backspace on empty input removes last tag
  • Blur (unfocus) automatically adds pending input as tag
  • Empty/whitespace-only tags are ignored
  • Duplicate detection trims and compares tags
  • When maxTags is reached, input becomes disabled
  • Focus ring appears around entire container
  • Chips size adjusts based on size prop
  • Click anywhere in container to focus input

Build docs developers (and LLMs) love