ComboBox
ComboBox is the single-selection, text-searching picker: type to narrow a list of options, move with the arrow keys, pick with Enter. It is for choosing an entity — a customer, a contact, a company — from options that may still be loading, may have failed to load, and may need an “add new” escape hatch.
Use Dropdown for choosing from a known, small set, or several values at once; its filter path is a filterable select, not an entity picker.
Controlled usage
Section titled “Controlled usage”import { ComboBox } from '@cratis/components/Common';
const [customerId, setCustomerId] = useState<string | null>(null);
<label htmlFor='customer'>Customer</label><ComboBox id='customer' options={customers.map(customer => ({ key: customer.id, label: customer.name, description: customer.orgNumber }))} value={customerId} onChange={setCustomerId} placeholder='Search customers' emptyMessage='No customer matches.'/>value is the selected option’s key or null. Selecting writes the option’s label into the input; clearing the text and leaving the field clears the selection. A value set from outside shows its label; options that arrive after mount with a key already chosen show its label too, unless the user is typing at that moment.
Filtering and searching
Section titled “Filtering and searching”filter | Behavior |
|---|---|
contains | Default. Options whose label contains the typed text, case-insensitively. |
startsWith | Options whose label starts with the typed text. |
none | options shown as given — for a consumer that filters or queries itself. |
onInputChange receives the text as it is typed, so a consumer can drive a server-side search and feed the result back through options with filter='none'. openOnFocus opens the list when the input receives focus, so a short roster is visible before anything is typed.
Not-ready states and the action row
Section titled “Not-ready states and the action row”loadingwithloadingMessageshows the message instead of options, as astatusregion marked busy.failurereplaces the options with the given content as analert.emptyMessageshows when nothing matches.actionrenders one row after the options — reachable by arrow keys, chosen with Enter or a click — and callsonAction(inputValue)with the typed text. The selection is unchanged.
Accessibility contract
Section titled “Accessibility contract”The input carries role="combobox" with aria-expanded, aria-controls and aria-activedescendant; the list is a listbox of options; a disabled option is aria-disabled. ArrowDown/ArrowUp move, Home/End jump, Enter selects, Escape closes, typing filters. Name the control through a visible <label htmlFor={id}>, aria-label or aria-labelledby; description and errorMessage render under the control and join aria-describedby; errorMessage also becomes aria-errormessage while invalid.
| Prop | Type | Default | Behavior |
|---|---|---|---|
options | ComboBoxOption[] | Required | key, label, optional description and disabled. |
value / onChange | string | null, (key) => void | Required | Controlled selected key. |
inputValue / onInputChange | string, (text) => void | Internal | Controlled or observed input text. |
filter | 'contains' | 'startsWith' | 'none' | contains | How typed text narrows options. |
openOnFocus | boolean | false | Opens the list on focus. |
loading / loadingMessage | boolean, ReactNode | false | Busy state instead of options. |
failure | ReactNode | — | Alert content replacing the options. |
emptyMessage | ReactNode | — | Shown when nothing matches. |
action | { label: string, onAction(inputValue) } | — | Footer row after the options; the label is its accessible name. |
optionLayout | 'inline' | 'stacked' | inline | Description beside or under the label. |
placeholder | string | — | Empty edit hint. |
disabled / readOnly / invalid / required | boolean | false | Semantic and visual state. |
id / name | string | Generated / — | Label association and native form field name (the selected key). |
description / errorMessage | ReactNode | — | Associated help and invalid-state content. |
pt | ComboBoxParts | — | Part classes, styles, titles and data attributes. |
Stable parts and tokens
Section titled “Stable parts and tokens”Typed pt key / DOM part | Meaning | Canonical states |
|---|---|---|
root | Complete control | disabled, invalid, readonly, loading |
input | The combobox input | disabled, invalid, readonly, open |
trigger | The open button | disabled, open |
popover / listbox | Portaled list | open / none |
option / optionLabel / optionDescription | One option and its texts | disabled, selected / none / none |
loading / empty / failure | The three not-ready messages | none |
action | The footer row | none |
description / error | Supporting text, validation message | none / invalid |
The component uses the shared control, surface, overlay, text, highlight, focus and disabled tokens and introduces none of its own. Use parts and tokens rather than internal element order or implementation-library selectors.