labsUI

Tag Input

Free-form tags: Enter or a separator adds, Backspace removes the last, pasting a list adds them all. Duplicates, a max and a validate function keep bad tags in the input. One hidden input per tag.

npx @kznlabs/labsui add tag-input
clutchvalorant

Enter or comma to add, Backspace to remove. Paste “a, b, c” to add several.

labsui.dev

Up to 3, must contain a dot.

"use client";import { useState } from "react";import { Field } from "@/components/ui/field";import { TagInput } from "@/components/ui/tag-input";export function ClipTags() {  const [tags, setTags] = useState<string[]>([]);  return (    <Field label="Tags" description="Enter or comma to add.">      <TagInput        name="tags"        value={tags}        onValueChange={setTags}        max={5}        validate={(t) => t.length <= 24}        placeholder="Add a tag…"      />    </Field>  );}

<TagInput>

Free-form tags: type and press Enter or a separator; paste a list to add many; Backspace in an empty input removes the last tag. name submits one hidden input per tag.

  • defaultValuedefault []
    string[]

    Tags at first render (uncontrolled).

  • max
    number

    Most tags allowed; typing stops at the limit.

  • onValueChange
    (tags: string[]) => void

    Called with every tag after an add or remove.

  • separatorsdefault [","]
    string[]

    Keys that commit the typed text, besides Enter. Pasted text is split on these too.

  • validate
    (tag: string) => boolean

    Return false to reject a tag (it stays in the input). Runs after trimming.

  • value
    string[]

    Controlled tags; pair with onValueChange.

PropTypeDefault
defaultValue

Tags at first render (uncontrolled).

string[][]
max

Most tags allowed; typing stops at the limit.

number—
onValueChange

Called with every tag after an add or remove.

(tags: string[]) => void—
separators

Keys that commit the typed text, besides Enter. Pasted text is split on these too.

string[][","]
validate

Return false to reject a tag (it stays in the input). Runs after trimming.

(tag: string) => boolean—
value

Controlled tags; pair with onValueChange.

string[]—

Also accepts every <input> prop.

<Tag>

Removable chip. Springs in and out when rendered inside AnimatePresence (mode="popLayout").

  • children*
    ReactNode

    Tag text.

  • disabled
    boolean

    Hides the remove button.

  • onRemove
    () => void

    Shows a remove button; its accessible name is "Remove <children>".

PropTypeDefault
children*

Tag text.

ReactNode—
disabled

Hides the remove button.

boolean—
onRemove

Shows a remove button; its accessible name is "Remove <children>".

() => void—

* required. Every component also takes className.