Tag Input
A multi-tag input built on Combobox with chips, free entry, CSV paste, and predefined options.
Overview
TagInput lets users add, remove, and select multiple tags. It supports predefined options, free-typed tags via Enter/comma, CSV/TSV/newline pasting, and backspace-to-remove on an empty input.
Usage
import { TagInput } from "@tilt-legal/cubitt-components/primitives";
const options = [
{ id: "react", label: "React" },
{ id: "ts", label: "TypeScript" },
{ id: "ui", label: "UI/UX" },
];
export default function Component() {
return <TagInput options={options} placeholder="e.g. TypeScript" />;
}Sync tags with the URL by providing paramName. The component serializes to a string array automatically.
// Synced with ?demo-tags=foo,bar (when tags are added)
<TagInput paramName="demo-tags" placeholder="Add tags..." />
// Advanced options
<TagInput
paramName="labels"
paramClearOnDefault
paramDebounce={300}
onUrlValueChange={(value) => console.log("tags:", value)}
/>Examples
Default (predefined options)
import { TagInput } from "@tilt-legal/cubitt-components/primitives";
const options = [
{ id: "react", label: "React" },
{ id: "ts", label: "TypeScript" },
{ id: "ui", label: "UI/UX" },
];
export default function Component() {
return <TagInput options={options} placeholder="Add tags" />;
}Free entry + remove last on backspace
import { useState } from "react";
import { TagInput } from "@tilt-legal/cubitt-components/primitives";
export default function Component() {
const [tags, setTags] = useState([]);
return (
<TagInput
tags={tags}
onTagsChange={setTags}
placeholder="Type and press Enter or ,"
/>
);
}Paste CSV/TSV/newlines
import { TagInput } from "@tilt-legal/cubitt-components/primitives";
export default function Component() {
return (
<TagInput
enableExcelPaste
pasteDelimiters={[",", "\n", "\t"]}
placeholder="Paste a CSV/TSV list"
/>
);
}Expanded field
Increase the field height when tags are likely to wrap across several rows or when you want a larger area to click and start typing.
import { useState } from "react";
import { TagInput } from "@tilt-legal/cubitt-components/primitives";
const initialTags = [
{ id: "contract-review", label: "Contract Review" },
{ id: "employment", label: "Employment" },
{ id: "urgent", label: "Urgent" },
];
export default function Component() {
const [tags, setTags] = useState(initialTags);
return (
<TagInput
className="w-full max-w-xs [&_[data-slot=combobox-chips]]:min-h-28 [&_[data-slot=combobox-chips]]:content-start [&_[data-slot=combobox-chips]]:items-start"
onTagsChange={setTags}
placeholder="Add tags"
tags={tags}
/>
);
}URL State
import { TagInput } from "@tilt-legal/cubitt-components/primitives";
// Synced with ?demo-tags=foo,bar
export default function Component() {
return <TagInput paramName="demo-tags" placeholder="Synced with ?demo-tags=" />;
}API Reference
TagInput
| Prop | Type | Default | Description |
|---|---|---|---|
tags | { id: string; label: string }[] | — | Controlled tags. |
defaultTags | { id: string; label: string }[] | — | Uncontrolled initial tags. |
onTagsChange | (next: Tag[]) => void | — | Change handler for controlled usage. |
options | { id: string; label: string }[] | — | Predefined selectable options. |
variant | "sm" | "md" | "lg" | "md" | Size variant. |
placeholder | string | — | Placeholder for the input. |
className | string | — | Additional className for the wrapper. |
inputProps | InputHTMLAttributes<HTMLInputElement> | — | Forward id/name/aria/blur to the inner input. |
allowDuplicates | boolean | false | Allow duplicate tag labels. |
enableExcelPaste | boolean | true | Split pasted CSV/TSV/newlines into tags. |
enableCommaDelimiter | boolean | true | Comma key creates a tag. |
pasteDelimiters | string[] | [",", "\n", "\r\n", "\t"] | Delimiters used when splitting pasted text. |
URL State Props
When paramName is provided, TagInput syncs its tags to a string[] URL parameter via TanStack Router search params.
| Prop | Type | Default | Description |
|---|---|---|---|
paramName | string | — | URL parameter name to sync. Enables URL state management. |
onUrlValueChange | (value: string[]|null) => void | — | Callback when URL parameter value changes. |
paramClearOnDefault | boolean | true | Remove URL param when value equals default. |
paramThrottle | number | — | Throttle URL updates in milliseconds. |
paramDebounce | number | — | Debounce URL updates in milliseconds. |