Combobox
import { Combobox } from '@absoluteui/components/combobox';import '@absoluteui/components/combobox/style.css';Using Angular? See Combobox for Angular.
What it does
Section titled “What it does”An editable single-select combobox with list autocomplete (WAI-ARIA 1.2), without automatic selection.
- DOM focus stays on the input; the active option is conveyed through
aria-activedescendant. - The listbox renders in the browser top layer (Popover API) and is positioned by the positioning engine.
When to use
Section titled “When to use”- Choosing one value from a list long enough to benefit from filtering (roughly 7+ options).
- Forms that submit a single option value.
When not to use
Section titled “When not to use”- Fewer than ~7 options: use a radio group or native select.
- Free-text entry with suggestions (custom values are not supported).
- Multiple selection: use Multi Select (or Checkbox Group for a few options).
Examples
Section titled “Examples”Single selection in a form
Section titled “Single selection in a form”import { Combobox, type ComboboxChangeDetail } from '@absoluteui/components/combobox';
const host = document.createElement('div');document.body.append(host);const country = Combobox.create(host, { label: 'Country', name: 'country', options: [ { value: 'in', label: 'India' }, { value: 'jp', label: 'Japan' }, { value: 'de', label: 'Germany' }, ],});host.addEventListener('aui-change', (event) => { const { value } = (event as CustomEvent<ComboboxChangeDetail>).detail; country.update({ invalid: value === null });});Required with an error message
Section titled “Required with an error message”import { Combobox } from '@absoluteui/components/combobox';
const host = document.createElement('div');document.body.append(host);Combobox.create(host, { label: 'Priority', required: true, invalid: true, errorMessage: 'Choose a priority.', options: [ { value: 'high', label: 'High' }, { value: 'low', label: 'Low' }, ],});import { Combobox, type ComboboxChangeDetail } from '@absoluteui/components/combobox';import '@absoluteui/components/combobox/style.css';
const host = document.querySelector<HTMLElement>('#fruit');if (host) { Combobox.create(host, { label: 'Fruit', options: [{ value: 'apple', label: 'Apple' }] }); host.addEventListener('aui-change', (e) => { console.log((e as CustomEvent<ComboboxChangeDetail>).detail.value); });}More usage
Section titled “More usage”import { Combobox } from '@absoluteui/components/combobox';
const host = document.createElement('div');document.body.append(host);Combobox.create(host, { label: 'Country', name: 'country', options: [ { value: 'in', label: 'India' }, { value: 'jp', label: 'Japan' }, ],});Anatomy
Section titled “Anatomy”<div class="aui-combobox"> (consumer host) <label class="aui-combobox__label" for=input> <div class="aui-combobox__control"> <input role="combobox" class="aui-combobox__input"> <button class="aui-combobox__toggle" tabindex="-1" aria-label="Show options"> </div> <div class="aui-combobox__description"> <div class="aui-combobox__error"> <input type="hidden" name> <div class="aui-combobox__popup" popover="manual"> <div role="listbox" class="aui-combobox__listbox"> <div role="option">... </div> <div class="aui-combobox__empty">No results</div> </div></div>API reference
Section titled “API reference”Factory
Section titled “Factory”Combobox.create(host: HTMLElement, options: ComboboxOptions): ComboboxGlobal configuration key: combobox (see Configuration).
Options
Section titled “Options”| Option | Type | Default | Description |
|---|---|---|---|
label |
string |
Visible label and accessible name. Required. | |
options |
readonly ComboboxOption[] |
{ value, label, disabled?, description? } with unique values. Required. | |
value |
string | null |
null |
Selected value. |
name |
string |
Form field name for the hidden input. | |
placeholder |
string |
Input placeholder (supplementary; never replaces the label). | |
description |
string |
Help text referenced by aria-describedby. | |
required |
boolean |
false |
Sets required and aria-required. |
disabled |
boolean |
false |
Disables the input and toggle. |
readOnly |
boolean |
false |
Prevents opening and editing. |
invalid |
boolean |
false |
Sets aria-invalid and shows errorMessage. |
errorMessage |
string |
Validation message shown when invalid. | |
icons |
Partial<{ expand: IconRef; selected: IconRef; error: IconRef }> |
Icon slot overrides. | |
renderOption |
(option: ComboboxOption, context: ComboboxRenderContext) => Node |
Custom option content (since 0.9.0); the label stays the accessible name. Nodes are released with releaseNode when dropped. | |
loadOptions |
(query: string, context: ComboboxLoadContext) => Promise<readonly ComboboxOption[]> |
Load options for the typed text instead of filtering options (since 0.9.0); debounced, stale requests aborted, loading and errors announced. | |
loadDelay |
number |
"250" |
Milliseconds between the last keystroke and loadOptions (0-5000). |
filter |
'contains' | 'startsWith' | 'none' |
"contains" |
Filtering strategy. Globally configurable. |
openOnFocus |
boolean |
false |
Open the listbox on focus/click. Globally configurable. |
clearOnEscape |
boolean |
true |
Escape with a closed listbox clears the value. Globally configurable. |
locale |
string |
"en-US" |
Messages and filtering locale. Globally configurable. Inherited from common configuration. |
direction |
'ltr' | 'rtl' |
"ltr" |
Popup alignment direction. Globally configurable. Inherited from common configuration. |
Properties
Section titled “Properties”| Property | Type | Description |
|---|---|---|
host |
HTMLElement |
Consumer-provided host (children are owned by the component). |
input |
HTMLInputElement |
The combobox input. |
listbox |
HTMLDivElement |
The listbox element. |
value |
string | null |
Selected value. |
selectedOption |
ComboboxOption | null |
Selected option. |
isOpen |
boolean |
Whether the listbox is shown. |
validity |
FieldValidity |
{ valid, error, message }. invalid/errorMessage options take precedence over the required check. |
name |
string | null |
Form field name. |
label |
string |
Label text. |
disabled |
boolean |
Disabled state. |
dirty |
boolean |
Value differs from the initial value. |
touched |
boolean |
Focus has left the control at least once. |
Methods
Section titled “Methods”| Method | Description |
|---|---|
setValue(value: string | null): void |
Programmatic selection (no aui-change). Unknown values clear the selection. |
update(options: Partial<ComboboxOptions>): void |
Merge and apply options. |
open(): void |
Show the listbox. |
close(): void |
Hide the listbox. |
destroy(): void |
Close, remove listeners, subscriptions, and rendered children. |
reportValidity(): boolean |
Show messages now and return validity. |
setCustomError(message: string | null): void |
External error (server, cross-field rule); cleared when the user changes the value. |
focus(): void |
Focus the control. |
reset(): void |
Restore the initial value and clear touched/submitted state (no aui-change). |
getFormValue(): string | null |
Selected value for form serialization. |
Events
Section titled “Events”| Event | Detail | Bubbles | Cancelable | Description |
|---|---|---|---|---|
aui-change |
{ value: string | null; option: ComboboxOption | null } |
Yes | No | User changed the selection. |
aui-input |
{ query: string } |
Yes | No | User edited the input text. |
aui-open |
null |
No | No | Listbox opened. |
aui-close |
null |
No | No | Listbox closed. |
CSS classes
Section titled “CSS classes”All rules live in the aui.components cascade layer, so application styles override them without specificity battles.
| Class | Purpose |
|---|---|
aui-combobox |
Host. |
aui-combobox--invalid | --disabled |
State modifiers on the host. |
aui-combobox__label |
Visible label. |
aui-combobox__control |
Input and toggle wrapper (popup anchor). |
aui-combobox__input |
Combobox input. |
aui-combobox__toggle |
Show-options button (not in tab order). |
aui-combobox__popup |
Top-layer popover container. |
aui-combobox__listbox |
Listbox. |
aui-combobox__option |
Option; –active marks the active descendant. |
aui-combobox__empty |
Empty-results message. |
aui-combobox__description | __error |
Help and error text. |
Icon slots
Section titled “Icon slots”| Slot | Default icon |
|---|---|
expand |
chevron-down |
selected |
check |
error |
alert-circle |
Design tokens
Section titled “Design tokens”Tokens this stylesheet reads (verified in CI). Override them in a theme or with the Theme Designer.
--aui-border-width | --aui-color-border | --aui-color-border-strong | --aui-color-disabled-bg | --aui-color-error-fg | --aui-color-focus-ring | --aui-color-hover | --aui-color-selected | --aui-color-selected-indicator | --aui-color-selected-text | --aui-color-surface | --aui-color-text | --aui-color-text-disabled | --aui-color-text-muted | --aui-control-height-md | --aui-control-height-sm | --aui-control-padding-x | --aui-duration-fast | --aui-easing-standard | --aui-focus-ring-offset | --aui-focus-ring-width | --aui-font-family-sans | --aui-font-size-md | --aui-font-size-sm | --aui-font-weight-medium | --aui-icon-size-sm | --aui-line-height-normal | --aui-line-height-tight | --aui-popover-max-height | --aui-radius-md | --aui-radius-sm | --aui-shadow-md | --aui-space-1 | --aui-space-2 | --aui-space-3
TypeScript definitions
Section titled “TypeScript definitions”interface ComboboxOption { readonly value: string; readonly label: string; readonly disabled?: boolean; readonly description?: string }interface ComboboxChangeDetail { value: string | null; option: ComboboxOption | null }type ComboboxFilter = 'contains' | 'startsWith' | 'none';Accessibility
Section titled “Accessibility”Pattern: WAI-ARIA APG Combobox pattern: editable combobox with list autocomplete, without automatic selection.
Keyboard
Section titled “Keyboard”| Key | Context | Action |
|---|---|---|
| ArrowDown | Closed | Opens; activates the selected option or the first enabled option. |
| ArrowUp | Closed | Opens; activates the selected option or the last enabled option. |
| Alt+ArrowDown | Closed | Opens without activating an option. |
| ArrowDown / ArrowUp | Open | Moves the active option, skipping disabled options, wrapping. |
| PageDown / PageUp | Open | Moves the active option by 10. |
| Enter | Open with an active option | Selects it, closes, emits aui-change. |
| Escape | Open | Closes the listbox; keeps the value. |
| Escape | Closed with a value, clearOnEscape=true | Clears the value. |
| Tab | Any | Closes the listbox and moves focus; free text reverts to the selected label. |
| Printable characters | Any | Edits the text, opens, and filters. |
| Element | Role |
|---|---|
| input | combobox |
| listbox container | listbox |
| each option | option |
| toggle button | button (native, tabindex=-1) |
ARIA attributes
Section titled “ARIA attributes”| Attribute | Element | Value |
|---|---|---|
aria-autocomplete |
input | list |
aria-expanded |
input and toggle | true when the listbox is shown |
aria-controls |
input and toggle | listbox id |
aria-activedescendant |
input | id of the active option; removed when none |
aria-selected |
option | true for the selected option |
aria-disabled |
option | true for disabled options |
aria-invalid / aria-required / aria-describedby |
input | Reflect invalid, required, description and error text |
DOM focus always stays on the input; options are never focused. The active option has a visible outline.
WCAG 2.2 success criteria addressed
Section titled “WCAG 2.2 success criteria addressed”Automated test results: Accessibility and compliance.
Notes and known caveats
Section titled “Notes and known caveats”- Result counts are announced via a polite live region after typing pauses.
- The toggle button is excluded from the tab order per the APG example; it has a localized accessible name.
- Manual screen-reader verification (NVDA, JAWS, VoiceOver, TalkBack) is pending.
Behavior
Section titled “Behavior”States
Section titled “States”closed, open, filtering, empty results, option active, option selected, option disabled, disabled, read-only, invalid, required.
State transitions
Section titled “State transitions”| From | Trigger | To |
|---|---|---|
| closed | ArrowDown/ArrowUp, typing, toggle click | open |
| open | Enter on an active option / option click | closed + selected (aui-change) |
| open | Escape, Tab, outside pointer, blur | closed (value unchanged; text reverts to the selected label) |
| closed (has value) | Escape with clearOnEscape |
cleared (aui-change with null) |
Accessibility notes
Section titled “Accessibility notes”- No automatic selection. Typing never changes the value until the user confirms.
- Result counts are announced in a shared polite live region, 400 ms after typing stops.
- The active option is outlined, so it does not rely on color alone (WCAG 1.4.1).
- Verified with axe (WCAG 2.2 AA) while open in 3 themes.
- Manual screen-reader verification is pending.
Responsive behavior
Section titled “Responsive behavior”The input fills its container, and the listbox matches the input width. The listbox flips above the input when space below is insufficient; this is verified at a 375x667 viewport. Height is capped by min(popover-max-height, available space).
Right-to-left
Section titled “Right-to-left”Logical properties throughout. Popup alignment follows the direction option or configuration.
Theming
Section titled “Theming”Token-driven. In forced-colors mode, the selected option uses Highlight/HighlightText and the active outline uses Highlight.
Global configuration
Section titled “Global configuration”configureAbsoluteUI({ components: { combobox: { filter: 'startsWith', openOnFocus: true } } });Component configuration
Section titled “Component configuration”Instance options override global and theme defaults. All configurable options are dynamic.
icons.expand (default chevron-down), icons.selected (default check), and icons.error (default alert-circle, since 0.2.0). Required fields show the shared visual-only asterisk.
Security
Section titled “Security”Labels and descriptions use textContent. Positioning writes styles through the CSSOM only, so no style attributes are used. Verified under a strict CSP with Trusted Types enforced.
Data handling
Section titled “Data handling”No persistence, network access, or telemetry. The hidden input holds the selected value when name is set.
Performance
Section titled “Performance”Filtering is O(n) per keystroke using a normalized comparison: NFD form, diacritics removed, locale lowercase. All filtered options are rendered.
Budgets in headless Chromium:
- create with 1,000 options: under 100 ms;
- filter keystroke with 1,000 options: under 50 ms.
Supported data scale
Section titled “Supported data scale”Tested with 1,000 options. Larger lists need virtualization, which is not available; use loadOptions to load matching options instead.
Edge cases
Section titled “Edge cases”- The popup is hidden by the browser until its first open, because
popover="manual"is set at construction. - Inside a modal dialog, the listbox renders above the dialog, and Escape closes the listbox before the dialog.
- Disabled options cannot be activated with the keyboard or clicked.
- Updating
optionsso the selected value no longer exists clearsvalue, the input text, and the hidden input. Noaui-changeis emitted, because the change is programmatic.
Errors
Section titled “Errors”| Code | Category | Cause |
|---|---|---|
COMBOBOX_OPTIONS |
configuration | Missing label, non-array options, malformed option, or duplicate value. |
CFG_INVALID_VALUE / CFG_UNKNOWN_OPTION |
configuration | Invalid or unknown configuration. |
Known limitations
Section titled “Known limitations”- Strict selection only; no custom values.
- No virtualization or option groups; one value only (use Multi Select for several).
- Substring or prefix matching only; no fuzzy search.
- Manual screen-reader verification is pending.
Unsupported scenarios
Section titled “Unsupported scenarios”- Custom option templates.
- Non-string option values.
- Duplicate values.