Combobox
Search and select from a list without leaving the field.
pnpm dlx shadcn@latest add @uiarc/comboboxLive · keyboard ready
- Single-choice fields with long lists, such as time zones or countries.
- Lists where people know the name and want to type, including aliases via keywords.
- Use select for a short list where typing adds nothing.
- Use multi-select when several values can be chosen.
- Use expanding-search when the search navigates instead of setting a value.
Installation
Add Combobox with the shadcn CLI, or copy the source by hand.
pnpm dlx shadcn@latest add @uiarc/comboboxAdds the component and its local dependencies, and installs motion, lucide-react. First time? Add the @uiarc registry to components.json, or use the full URL:
example.tsx
import { Combobox } from "@/registry/components/combobox/combobox"; const timezones = [ { value: "utc", label: "UTC" }, { value: "cet", label: "Central European", keywords: ["zurich", "berlin"] }, { value: "pst", label: "Pacific", keywords: ["san francisco"] },]; export function TimezoneField() { const [zone, setZone] = useState(""); return <Combobox label="Time zone" options={timezones} value={zone} onValueChange={setZone} />;}Combobox
A searchable single-select field: type to filter, pick from a listbox that follows its height on a spring.
PropTypeDefaultDescription
labelRequiredstring–Visible label, also used to name the listbox.optionsRequiredComboboxOption[]–{ value, label, disabled?, keywords? }. Keywords also match the query.valuestring–Controlled selected value. Empty string means none.defaultValuestring""Initial value when uncontrolled.onValueChange(value: string) => void–Called with the new value, or an empty string when cleared.descriptionstring–Helper copy under the field, linked through aria-describedby.placeholderstring"Search or select…"Shown when nothing is selected. While searching, the chosen label shows here instead.emptyMessagestring"No matches found"Shown in a status row when the filter matches nothing.classNamestring–Added to the control wrapper....propsOmit<InputHTMLAttributes<HTMLInputElement>, "value" | "defaultValue" | "onChange" | "placeholder">–Forwarded to the input, including ref, id, name, disabled, and onFocus.- ArrowDownorArrowUp
- Opens the list, then moves through enabled options, wrapping at the ends.
- Enter
- Selects the active option.
- Escape
- Closes the list and discards the query.
- Input has role="combobox" with aria-expanded, aria-controls, aria-autocomplete="list", and aria-activedescendant.
- Options use role="option" with aria-selected and aria-disabled; the list is labelled "<label> options".
- The empty state is a role="status" row; the clear button is labelled "Clear selection".
- The popover springs in from slightly above and the listbox height follows filtering on a smooth spring.
- A chosen label rises into the field with a soft blur; the clear button scales in.
- Reduced motion keeps opacity-only fades and instant height changes.
- The popover spans the field width and the listbox caps at min(300px, 40vh), scrolling with contained overscroll.
- It closes on any pointerdown outside, so a tap elsewhere dismisses it on touch.
- Filtering is memoized and runs on every keystroke across all options; results are not virtualized, so pre-filter very large lists.
- A ResizeObserver drives the listbox height spring while filtering.
Notes for AI
Give your coding assistant the Markdown reference instead of screenshots.
- Use for long or searchable single-choice lists. Use select for short lists, multi-select for several values, and expanding-search for search that navigates.
- Controlled with value and onValueChange, or uncontrolled with defaultValue. The input shows the label, not the value, so pair name with a hidden input if you post a form.
- Add keywords to options for synonyms and aliases.
The full library index for assistants is at /llms.txt.