Combobox

Search and select from a list without leaving the field.

pnpm dlx shadcn@latest add @uiarc/combobox
Live · 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/combobox

Adds 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.
/components/combobox/markdown

The full library index for assistants is at /llms.txt.