Multi-select whose picks become chips in the field: chips pop in with a spring and fold into “+N”, options tick a drawn checkbox, arrows walk the chips and Backspace removes them, with Reset and Select all in the footer.
multi-selectselectchipstagslistboxform
Installation
$npx shadcn@latest add @geturui/tag-select
Usage
usage.tsx
1import { TagSelect } from "@/components/ui/tag-select";
2
3const reviewers = [
4 { value: "maya", label: "Maya Okafor", description: "Design lead", avatar: true },
5 { value: "theo", label: "Theo Lindqvist", description: "Frontend", avatar: true },
6 { value: "priya", label: "Priya Raman", description: "Design systems", avatar: true },
7];
8
9export function ReviewersField() {
10 return <TagSelect label="Reviewers" options={reviewers} defaultValue={["maya"]} max={2} name="reviewers" />;
11}
Props
| Prop | Type | Default | Description |
|---|---|---|---|
options* | TagSelectEntry[] | — | { value, label, description?, icon?, avatar?: boolean | string, dot?: "success" | "warning" | "danger" | "info" | "neutral", meta?, shortcut?, disabled?, keywords? }, a group { heading, options } or { separator: true } |
value / defaultValue | string[] | — | Selected values in pick order. |
onValueChange | (value: string[]) => void | — | Fires on every toggle, removal, reset or select all. |
size | "sm" | "md" | "lg" | "md" | Well height 32 / 40 / 48, matching Button. Rows, icons and the list height scale with it. |
label / hint / error | ReactNode | — | Field chrome. Any error marks the control invalid and swaps the hint for the message. |
required | boolean | false | Volt asterisk on the label and aria-required on the control. |
disabled | boolean | false | Dims the well and blocks interaction. |
name | string | — | Form field name; values post through hidden inputs. |
placeholder | string | "Select options" | Shown while nothing is picked. |
maxVisible | number | 3 | Chips shown before the rest collapse into “+N”. |
max | number | — | Most options that can be picked; the others disable once it's reached. |
searchable | boolean | true | Search box at the top of the panel, with a Clear search link when nothing matches. |
footer | boolean | true | Selected count with Reset and Select all (Select all respects the search and max). |
iconLeading | ComponentType<{ className }> | — | Icon at the start of the well. |
Accessibility
- The listbox is aria-multiselectable; Enter (and Space without search) toggles the highlighted option and the panel stays open.
- ⌘/Ctrl+A selects or clears every visible option when focus is on the trigger.
- Left arrow or Backspace on the trigger moves into the chips; Left/Right/Home/End walk them, Backspace or Delete removes one and focus lands on its neighbour.
- Each chip's remove button is labelled “Remove name”; the “+N” chip reads out the hidden names.
- The footer count is a polite live region.