Combobox
Search and select from a list without leaving the field.
$ pnpm dlx shadcn@4.23.0 add @xzero-ui/combobox- Type: Component (inputs)
- Access: Free, open source
- Page: https://ui.xzero.co.uk/components/combobox
- Markdown: https://ui.xzero.co.uk/components/combobox/markdown
- Registry item: https://mcp.xzero.co.uk/r/combobox.json
- Source file:
registry/components/combobox/combobox.tsx - Dependencies: motion, lucide-react
- Keywords: field, search, react combobox, autocomplete, searchable select, typeahead dropdown, filterable select, autocomplete input
When to use
- 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.
When not to use
- 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
Register both Xzero UI namespaces in your project's components.json:
{
"registries": {
"@xzero-ui": "https://mcp.xzero.co.uk/r/{name}.json",
"@xzero-ui-pro": "https://mcp.xzero.co.uk/r/pro/{name}.json"
}
}
npx shadcn@4.23.0 add @xzero-ui/combobox
Install xzero-foundation once, and import @/components/xzero/foundation.css in your app root. No Xzero token is used by this snapshot. For sample portraits, photos, fonts, or logos, download https://mcp.xzero.co.uk/install-assets.mjs and run node xzero-install-assets.mjs <receiving-project>.
Usage
import { Combobox } from "@/components/xzero/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} />;
}
API reference
Combobox
A searchable single-select field: type to filter, pick from a listbox that follows its height on a spring.
| Prop | Type | Default | Description |
|---|---|---|---|
label (required) | string | – | Visible label, also used to name the listbox. |
options (required) | ComboboxOption[] | – | { value, label, disabled?, keywords? }. Keywords also match the query. |
value | string | – | Controlled selected value. Empty string means none. |
defaultValue | string | "" | Initial value when uncontrolled. |
onValueChange | (value: string) => void | – | Called with the new value, or an empty string when cleared. |
description | string | – | Helper copy under the field, linked through aria-describedby. |
placeholder | string | "Search or select…" | Shown when nothing is selected. While searching, the chosen label shows here instead. |
emptyMessage | string | "No matches found" | Shown in a status row when the filter matches nothing. |
className | string | – | Added to the control wrapper. |
...props | Omit<InputHTMLAttributes<HTMLInputElement>, "value" | "defaultValue" | "onChange" | "placeholder"> | – | Forwarded to the input, including ref, id, name, disabled, and onFocus. |
Keyboard interactions
| Keys | Action |
|---|---|
| ArrowDown / ArrowUp | 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. |
Accessibility
- 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".
Motion
- 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.
Responsive behavior
- 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.
Performance
- 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
- 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.
Related
- Select: A compact choice field with a keyboard friendly menu.
- Multi-select: Select several values while keeping the field readable.
- Expanding search: An icon that morphs into a search field with results beneath it.
- Search field: A recognizable search entry point with clear affordances.
Also in selects
- Morph select: A select whose trigger grows into the list, with a gliding highlight and type-ahead.
- Chip group: Filter by a few facets with chips that morph as you pick them.
Guidance for AI tools
Combobox: Search and select from a list without leaving the field. Follow the declared prop types and do not invent props. Keep keyboard access, reduced motion support, and both light and dark themes intact when adapting it.
Full library index: https://ui.xzero.co.uk/llms.txt