MultiCombobox
v1.0.22Updated 20 Oct 2026Dedicated multi-select combobox: a searchable Popover + Command list whose trigger holds one removable chip per selection plus a "+N more" count once the list exceeds `maxDisplay`. Uses a values/onValuesChange array API rather than Combobox's discriminated single/multiple union, so state stays a plain string[]. Chips are removable by mouse, and Backspace in an empty search field drops the last value.
Preview
Live · 8 stories▸Why this is recommendedmulti-selectcomboboxchipstags+5
MultiCombobox — select.
- ✓Picking several projects or sites on a form
- ✓Tag or label pickers with a fixed vocabulary
- ✓Assigning multiple owners or reviewers
- ✓Selecting which columns or fields to show
- ✓Multi-select filters on a report or dashboard
- Multi-select with removable chips in the trigger
- "+N more" overflow count via `maxDisplay`
- Backspace in the empty search field removes the last value
- Flat or grouped options with headings and separators
- Plain string[] value API (values / onValuesChange)
- Custom trigger via the `trigger` prop
- Server-side filtering hook via `onSearchChange`
- Labelled by FormField: id and aria-* land on the role=combobox trigger, which then fills the field column
- ✕Selecting exactly one value (use Combobox)
- ✕Options fetched per keystroke with loading and error states (use ComboboxAsyncMulti)
- ✕Free-text tag entry where users invent values (use TagInput)
- ✕Small fixed sets of 2-5 options (use Checkbox group)
Install
Ask your agent, or call the MCP tool directly. The resolved bundle is written into your project.
Usage
Tick variants in the left menu — each adds a tab with that variant’s real story source, the same code the preview above renders.
Props
optionsFlat or grouped options; grouped entries render headings with separators
yesvaluesSelected values (default [])
—onValuesChangeFires with the next array on toggle or chip removal
—maxDisplayHow many chips render inline before collapsing to "+N more" (default 3)
—placeholderTrigger text when nothing is selected (default "Select…")
—searchPlaceholderPlaceholder for the filter input (default "Search…")
—emptyMessageShown when no option matches (default "No results.")
—onSearchChangeCalled as the user types — use it to fetch/filter options server-side. Also called with an empty string when the popover closes, because the search field is discarded with it, so a host that mirrors the query never keeps a stale one
—onOpenChangeFires on every open and close of the popover, including the programmatic close after a selection
—triggerReplace the default trigger button; the forwarded ref stays on the default trigger
—disabledDisable the trigger
—contentClassNameClass applied to the popover content
—scrollbarHow the option list draws its scrollbar once it overflows — forwarded to CommandList. Default 'thin': a visible themed bar, because the height cap is the only thing hiding the remaining options
—listMaxHeightCap the option list's height (number = px, string = any CSS length such as '50vh'). Omitted, the list keeps CommandList's 18rem default
—idDOM id set on the trigger — a <label htmlFor> (or FormField) names the control through it
—aria-labelAccessible name for the trigger when there is no visible label
—aria-labelledbyId(s) of the visible label element(s) that name the trigger
—aria-describedbyId(s) of hint or error text that describe the trigger
—aria-invalidMark the trigger invalid — FormField clones this in from its error prop
—aria-requiredMark the trigger required — FormField clones this in from its required prop
—invalidMark the field invalid (destructive ring); aria-invalid wins when both are set
—requiredMark the field required (aria-required on the trigger)
—classNameClass applied to the trigger; a width here wins over the default (w-full inside a FormField, the standalone width otherwise)
—