Skip to content
Component installs need the registry setup— the Base UI shadcn project, the @vegastack namespace and the Cloudflare Access service token.
VegaStack Design

Chip Input

Free-token entry — Enter or comma commits, delimited pastes split into chips, and per-chip validation keeps invalid entries visible instead of dropping them.

Status
stable
Since
0.4.0
Accessibility pattern
labelled token input

Last updated

Tags
designtokensSome entries are invalid

Enter or comma commits; Backspace in the empty input removes the last chip.

Install

Add Chip Input from the VegaStack registry. The CLI verifies the item's integrity hash before writing it.

pnpm dlx shadcn@latest add @vegastack/chip-input

The same command installs the registry items it composes: @vegastack/input, @vegastack/tag-group, @vegastack/use-announcer.

Usage

import { ChipInput } from "@/components/ui/chip-input";

<ChipInput aria-label="Tags" value={tags} onValueChange={setTags} />;

ChipInput fills the gap neither existing component can: TagGroup is a display list with no input, and Combobox's value model is selection-from-items — it cannot commit an arbitrary token. The field chrome is the Combobox input group's, the chips are real Tags (24px remove targets included), and the inner control is the real Input.

Scope

BehaviourWhere it lives
Suggestions / autocompleteA Combobox composition — deliberately not built in
Persisting the listHost, via onValueChange
Chip colour semanticsNot here — Tag hue is decorative; invalid is the only state
+N overflow collapseTagGroup — display-list semantics, wrong for an editable field

Examples

Per-chip validation

Entries are added and marked, not silently dropped: a pasted list of twenty addresses with two typos shows twenty chips with two flagged (data-invalid, destructive border) — and the field stays invalid until they are fixed or removed.

Recipients
ada@example.comnot-an-email, invalid entrySome entries are invalid

Invalid entries stay visible and flagged — paste a list and fix the typos instead of losing them.

Sizes and states

Some entries are invalid
events.createevents.deleteSome entries are invalid
lockedSome entries are invalid

API Reference

PropTypeDefaultDescription
allowDuplicatesbooleanfalseAllow the same chip twice. When false, a duplicate entry is rejected and announced.
aria-labelstringAccessible name for the inner input. The control must never be unnamed.
classNamestringExtra classes for the field group root.
defaultValuestring[][]Initial chips for uncontrolled use.
disabledbooleanfalseDisables the field and every chip's remove button.
inputRefReact.Ref<HTMLInputElement>Ref forwarded to the inner <input>.
normalize((raw: string) => string)(raw) => raw.trim()Normalise a raw entry before it is committed (and before duplicate checking). The default trims whitespace.
onValueChange((value: string[]) => void)Fired with the next chip list on every add or remove.
placeholderstringPlaceholder for the inner input while the field has room.
refReact.Ref<HTMLDivElement>Ref forwarded to the group root <div> (data-slot="chip-input").
size"lg" | "md" | "sm"
splitOnRegExp/[,\n]/Pattern the paste handler splits on, in addition to the Enter/comma commit keys.
validate((chip: string) => boolean)Per-chip validity. Invalid entries are still **added**, marked with data-invalid on their chip, described as invalid for assistive tech, and flip the whole field invalid until fixed or removed — a pasted list keeps every entry visible instead of silently dropping the malformed ones.
valuestring[]Controlled chip list. Pair with onValueChange; omit for uncontrolled use.

Data attributes and CSS variables on ChipInput

AttributeValues
data-disabled""
data-field-group""
data-invalid""
data-sizemirrors a prop or state value
data-slot"chip-input"

Accessibility

  • The inner input must carry an accessible name (aria-label) — it is the control assistive tech interacts with.
  • Accepted, invalid, duplicate, and removed outcomes are announced through a polite live region; invalid chips also carry a text description, never colour alone.
  • Every chip's remove button is named (Remove …) with a 24px hit area (from Tag).
  • The field border reflects focus (focus-within tint) and validity (data-invalid destructive tint), matching the Combobox input group.
KeyAction
Enter / ,Commit the draft as a chip.
Backspace (empty input)Remove the last chip.
TabMove between the input and chip remove buttons.
ContractStates tested
Behaviourempty, chips, invalid-chip, duplicate-rejected, disabled
Accessibilitykeyboard, labeled, status-announcement, semantic-html
Visualdefault, focus, invalid, disabled, dark

Do / Don't

Do
Validate per chip and let malformed entries stay visible and flagged — the user pasted them for a reason.
Don't
Reject invalid entries silently on commit — a dropped address in a 20-recipient paste is data loss the user won't notice.

On this page