/// Inputs
Combobox
Autocomplete field — a sunken input that filters a list as you type, following the ARIA 1.2 combobox pattern.
import { Combobox } from "@protocore/pds";Basics
Pass options with value / label and an optional trailing hint. Type to filter by label; arrow keys and Enter commit the selection.
Clearable & controlled
Set clearable for an inline × once a value is chosen. Drive value from state and read onValueChange — it fires with undefined when cleared.
Settling on base
Sizes
size matches the control scale used by Input and Select: sm (32) · md (36, default) · lg (40).
When to use it
Reach for a Combobox when the option list is long or unbounded and typing to narrow it is the fastest path — a service, a chain, a MIME type, a country. For a short, fixed list where filtering adds nothing, a Select is simpler. Use SearchInput when the query hits a backend and there's no closed set of options to pick from. Provide a custom filter when the default case-insensitive label match isn't what you want (e.g. matching on value or fuzzy scoring).
Usage
Do
- Give the input an accessible name via `aria-label` or a wrapping `Field`.
- Keep `options` label text meaningful — the default filter matches on `label`.
- Use `hint` for a compact secondary tag (a category, a shortcut), not a sentence.
- Make it `clearable` when 'no selection' is a valid, reachable state.
Don't
- Don't use a Combobox for 2–5 options — a Select or SegmentedControl is clearer.
- Don't pack long descriptions into `label`; the row is a single line.
- Don't reuse it as a freeform text box — it commits to one of the `options`.
- Don't leave it unlabelled; screen readers announce it as a combobox with no name.
Accessibility
| Keys | Action |
|---|---|
| Type | Filter the list; opens the popup and highlights the first match. |
| Arrow Down / Up | Move the active option (opens the popup if closed). |
| Home / End | Jump to the first / last option while open. |
| Enter | Select the active option and close. |
| Esc | Close the popup and restore the current selection's label. |
- Implements the ARIA 1.2 combobox pattern: focus stays on the `role="combobox"` input while `aria-activedescendant` points at the highlighted `role="option"`.
- The input exposes `aria-expanded`, `aria-controls`, and `aria-autocomplete="list"`.
- An empty filtered list announces a 'No results' row rather than collapsing silently.
Combobox props
| Prop | Type | Default | Description |
|---|---|---|---|
aria-label | string | — | Accessible label for the input (required if no visible label wraps it). |
className | string | — | Merged after the pds class on the root field. |
clearable | boolean | false | Show a clear (×) button once a value is selected. |
defaultValue | string | — | Initial selected value in uncontrolled mode. |
disabled | boolean | false | Disable the control. |
filter | ((options: ComboboxOption[], query: string) => ComboboxOption[]) | (options: ComboboxOption[], query: string): ComboboxOption[] => {
const q = query.trim().toLowerCase();
if (!q) return options;
return options.filter((o) => o.label.toLowerCase().includes(q));
} | Custom filter predicate; defaults to case-insensitive label substring match. |
id | string | — | Root id — also seeds the listbox/option ids. |
onValueChange | ((value: string) => void) | — | Fires with the newly selected value, or `undefined` when cleared. |
options * | ComboboxOption[] | — | The full option set. |
placeholder | string | Select… | Placeholder for the empty field. |
size | enum | md | Control height: `sm` (32) · `md` (36, default) · `lg` (40). |
value | string | — | Controlled selected value. |