Tag input

Creates and removes freeform text tokens with paste splitting, duplicate prevention, and validation.

  • Research
  • Design

Press Enter or comma to add a tag, up to 5

Name the work

Project keywords

Create a few useful labels. Paste a comma-separated list to add several at once.

  • Research
  • Design

Press Enter or comma to add a tag, up to 5

Use it for

  • Short freeform labels, recipients, or keywords.
  • Comma-separated or newline-separated pasted values that should become distinct tokens.

Not for

  • A fixed vocabulary; use MultiSelect.
  • Long prose; use Textarea.

Three ways in. They share one source, so the pixels match whichever you pick.

1. Import the package

npm install @noorddev/vlak-react

// once, next to your app's root
import "@noorddev/vlak-react/css";

import { TagInput } from "@noorddev/vlak-react";

Precompiled React and one stylesheet. No compiler to configure. Per-component imports work too: @noorddev/vlak-react/components/tag-input.

2. Vendor the source

npx @noorddev/vlak-cli add tag-input

The StyleX leaf lands in components/vlak/ with its dependencies, for your own compiler to own. See StyleX.

3. Through shadcn

npx shadcn add https://vlak.dev/r/tag-input.json

The same registry item, installed by shadcn's CLI.

CSS only

<link rel="stylesheet" href="node_modules/@noorddev/vlak/css/vlak.css" />

No React. Link vlak.css and use the markup and classes below.

import { TagInput } from "@noorddev/vlak-react";

<TagInput label="Project tags" name="tags" defaultValue={["Research", "Design"]} maxTags={5} validate={(tag) => tag.length > 24 ? "Use 24 characters or fewer" : undefined} />

TagInput

PropTypeDefaultDescription
valuestring[]
defaultValuestring[][]
onValueChange(value: string[]) => void
labelReactNode"Tags"
namestring
disabledboolean
placeholderstring"Add a tag"
maxTagsnumber
validate(tag: string) => stringReturn an error for an invalid token, or undefined to accept it.
addLabelstring"Add"
removeLabel(tag: string) => string(tag) => `Remove ${tag}`

Also accepts Omit<HTMLAttributes<HTMLDivElement>, "onChange" | "defaultValue">.

KeysDoes
Enter, commaCommits a trimmed draft as a tag without submitting the form.
Backspace in an empty inputFocuses the last tag's remove button.
EscapeClears the current draft and its error.
Tab, Enter, SpaceReaches and activates named Add and Remove buttons.
<div class="rs-tag-input"><label class="rs-tag-input-label" for="project-tags">Project tags</label><ul class="rs-tag-input-list" aria-label="Current tags"><li class="rs-tag-input-tag">Design<button class="rs-btn-ghost rs-tag-input-remove" type="button" aria-label="Remove Design">×</button></li></ul><div class="rs-tag-input-row"><input class="rs-input rs-tag-input-input" id="project-tags" placeholder="Add a tag" /><button class="rs-btn-ghost rs-tag-input-add" type="button">Add</button></div></div>
.rs-tag-input.rs-tag-input-label.rs-tag-input-list.rs-tag-input-tag.rs-tag-input-remove.rs-tag-input-row.rs-tag-input-input.rs-tag-input-add.rs-tag-input-feedback