Combobox
Autocomplete input and command palette with a list of suggestions.
Combobox is a searchable select. The trigger button shows the selected value; clicking it opens a popover with a search input and a filterable list of options. The selected value is written to a hidden input for form submission.
Compare with Select (native or custom dropdown without search). Use Combobox once the list goes past ~10 options, where search becomes necessary.
Installation
$ bext ui add combobox
Copy and paste the following into src/components/ui/combobox.tsx.
This component is interactive. Make sure the shared island is loaded (see Islands). It reacts to data-ui="combobox" hooks.
Usage
Anatomy
<Combobox name="…" value={value} options={[...]} />
├── <input type="hidden" name value />
├── <button data-ui-cb-trigger>
│ ├── <span>{label or placeholder}</span>
│ └── <ChevronDown />
└── <div data-ui-cb-pop>
├── <input data-ui-cb-search placeholder={searchPlaceholder} />
└── <div data-ui-cb-list>
└── <div data-ui-cb-item data-value>{label}</div> × NAPI Reference
Combobox
| Prop | Type | Default | Description |
|---|---|---|---|
| name | string | — | Name of the hidden input for form submission. |
| value | string | — | Selected value (matches options[].value). |
| options | ComboboxOption[] | — | List of { value, label, disabled? }. |
| placeholder | string | "Sélectionner…" | Trigger text when empty. |
| emptyLabel | string | "Aucune option." | Message shown when the list has no option at all. |
| searchPlaceholder | string | "Rechercher…" | Placeholder of the search field. |
| noResultLabel | string | "Aucun résultat." | Message shown when the search has no match. |
| required | boolean | — | Sets required on the hidden input. |
| disabled | boolean | — | Disables the trigger. |
| triggerWidth | string (utility) | "w-[240px]" | Width of the trigger button. |
Data Attributes
Attributes you can target in custom CSS to override the style for each state.
| Attribute | On | Values | Description |
|---|---|---|---|
| data-ui="combobox" | root | — | Root marker. |
| data-ui-cb-trigger | trigger button | — | Clicking opens or closes the popover. |
| data-ui-cb-search | input | — | Fuzzy-filter input: the island filters items by data-label. |
| data-ui-cb-item | each option | data-value data-label data-disabled? | Clicking sets the value and closes. |
| data-ui-cb-empty | div | hidden by default | Shown when no item matches. |
Keyboard
| Key | Action |
|---|---|
| Enter / Space | On a closed trigger: opens. On an item: selects and closes. |
| Escape | Closes the open popover. |
| Typing | Focus moves to the search input; typing filters in real time. |
Accessibility
The trigger carries aria-haspopup="listbox" aria-expanded. The list carries role="listbox", items role="option".
The hidden input is a real form field, so native HTML5 validation (required) works.
Examples
Placeholder (empty)
<Combobox name="x" options={…} placeholder="Choose one" />
Edit this component live in the bext playground. The PRISM + signals version is the bext-native idiom: fine-grained reactivity, no virtual DOM.
On This Page