A text input that filters a list of options as you type, for one value or several shown as chips, with async results.
Example
import {
Combobox, ComboboxItem, ComboboxGroup, ComboboxRow, ComboboxLabel, ComboboxSeparator,
} from "@elements/ui/combobox";
<Combobox value={form.framework} items={FRAMEWORKS} placeholder="Select a framework" label="Framework" />
<Combobox multiple values={form.tags} placeholder="Add tags" name="tags">
<ComboboxItem e:for={tag of TAGS} value={tag.id}>{tag.name}</ComboboxItem>
</Combobox>
<Combobox inputValue={search.q} filter={null} loading={search.loading} value={form.user}
onInputValueChange={(q) => find(search, q)}>
<ComboboxItem e:for={u of search.results} value={u.id}>{u.name}</ComboboxItem>
</Combobox>
Parts
| Part |
What it is |
Combobox |
The root: the input chrome (chips, input, clear and trigger buttons), the hidden form input and the listbox popup. |
ComboboxItem |
An option. Filtering hides it when its text and keywords do not match. |
ComboboxGroup |
A labelled group, hidden while none of its items match. |
ComboboxRow |
With grid: a row of items, which become its cells. Hidden while none of its items match. |
ComboboxLabel |
A label row the keyboard skips. |
ComboboxSeparator |
A line between groups, hidden while a query filters. |
Slots
| Slot |
Part |
Content |
default |
|
ComboboxItem, ComboboxGroup, ComboboxRow, ComboboxLabel and ComboboxSeparator parts, after any items. |
default |
ComboboxRow |
The row's ComboboxItem cells. |
empty |
|
Replaces emptyText when nothing matches. |
start |
|
An icon or text inside the input chrome, before the input. |
default |
ComboboxItem |
The option's content. |
indicator |
ComboboxItem |
Replaces the check shown while selected. |
Keyboard
| Keys |
Action |
Typing |
Opens the list and filters it. |
ArrowDown |
Opens on the selected option (or the first); then moves down. Past the last, back to the input; again, the first. |
ArrowUp |
Opens on the last option; then moves up. Past the first, back to the input; again, the last. |
Alt + ArrowDown |
Opens without highlighting an option. |
Alt + ArrowUp |
Closes the list. |
PageUp / PageDown |
Moves ten options. |
Enter |
Picks the highlighted option. |
Escape |
Closes the list; single selection puts the selected label back in the input. Typed text that chose nothing stays. |
Escape (closed) |
Clears typed text that chose nothing. |
ArrowDown / Enter / Space on the trigger |
inputInPopup: opens with focus in the search input. |
ArrowLeft / ArrowRight / Home / End |
Move the caret, and give the highlight back to the input. |
Backspace |
multiple, in an empty input: removes the last value, counted in "+N more" when chipLimit hides it. |
ArrowLeft at the start |
multiple: moves to the chips; Left and Right move between them, Right past the last returns to the input. |
Backspace / Delete on a chip |
Removes it. |
Tab |
Closes and moves on; typed text that chose nothing clears. |
Arrows (grid) |
With grid: Up and Down move to the same column of the next row, Left and Right to the next cell (across rows); with nothing highlighted, Left and Right move the caret. |
Home / End, Ctrl + Home / End (grid) |
With grid and a cell highlighted: the row's first and last cell; the grid's first and last cell. |
Data attributes
| Attribute |
Values |
On |
Description |
data-state |
"open" | "closed" |
.combobox-content |
|
data-anchor-hidden |
present |
.combobox-content |
While the input is scrolled out of view; the popup is hidden. Never with sticky. |
data-side, data-align |
side, alignment |
.combobox-arrow |
Where the arrow sits, after a flip. |
data-uncentered |
present |
.combobox-arrow |
The arrow cannot point at the input's middle. |
data-state |
"open" | "closed" |
.combobox-arrow, .combobox-backdrop |
|
data-popup-open |
present |
.combobox-control, .combobox-input, .combobox-trigger, .combobox-clear |
|
data-popup-side |
"top" | "bottom" |
.combobox-control, .combobox-input, .combobox-trigger |
The open popup's side. |
data-list-empty |
present |
.combobox-control, .combobox-input, .combobox-trigger |
Nothing matches. |
data-placeholder |
present |
.combobox-control |
Nothing is selected. |
data-pressed, data-focused |
present |
.combobox-control, .combobox-input |
During a press; while focus is inside. |
data-filled, data-dirty, data-touched |
present |
.combobox-control, .combobox-input, .combobox-trigger |
Has a value; the value changed from the first one; focus has left once. A form reset clears dirty and touched. |
data-valid |
present |
.combobox-control, .combobox-input |
The enclosing Field is valid. |
data-empty |
present |
.combobox-content |
Nothing matches. |
data-loading |
present |
.combobox-content |
|
data-invalid, data-disabled, data-readonly, data-required |
present |
.combobox-control |
|
data-invalid |
present |
.combobox-input |
aria-invalid is true (invalid, or a Field). |
data-visible |
present |
.combobox-clear |
There is something to clear. |
data-disabled |
present |
.combobox-clear |
|
data-highlighted |
present |
.combobox-item |
|
data-selected |
present |
.combobox-item |
|
data-state |
"checked" | "unchecked" |
.combobox-item |
|
data-disabled |
present |
.combobox-item |
|
data-side |
"top" | "bottom" | "left" | "right" |
.combobox-content |
|
data-align |
"start" | "center" | "end" |
.combobox-content |
|
--combobox-columns |
number |
.combobox-list |
With grid: how many equal columns each row has (default 4). Set it in your CSS. |
--anchor-width |
px |
.combobox-content |
The control's width; the popup is at least this wide. |
--available-height |
px |
.combobox-content |
|
--anchor-height, --available-width, --transform-origin |
px, px, position |
.combobox-content |
|
Accessibility
- The input is the APG editable combobox with list autocomplete: role="combobox", aria-autocomplete="list", aria-expanded, aria-controls the listbox.
- Focus stays in the input; aria-activedescendant names the highlighted option. Editing the text gives the highlight back to the input.
- With grid the popup is role="grid" (aria-haspopup="grid" on the input), each ComboboxRow role="row" and its items role="gridcell".
- Options carry aria-selected; the listbox has aria-multiselectable with multiple and aria-busy while loading.
- After typing settles, a polite live region says how many results there are.
- Chips are focusable with the arrow keys; each remove button is named "Remove
<label>".
- The clear and trigger buttons are out of the Tab order (the input is the one stop) and keep focus in the input when pressed.
See also