bx

Combobox

Autocomplete input and command palette with a list of suggestions.

tsx
<Combobox
  name="framework"
  value="next"
  options={[
    { value: "next", label: "Next.js" },
    { value: "sveltekit", label: "SvelteKit" },
    { value: "nuxt", label: "Nuxt.js" },
  ]}
  searchPlaceholder="Search…"
  noResultLabel="No results."
/>

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

Terminal
$ bext ui add combobox

Usage

tsx
import { Combobox } from "@bext-stack/ui/primitives"

<Combobox
  name="framework"
  value={value}
  options={[
    { value: "next", label: "Next.js" },
    { value: "sveltekit", label: "SvelteKit" },
    { value: "nuxt", label: "Nuxt.js" },
    { value: "remix", label: "Remix" },
  ]}
  placeholder="Choose a framework"
/>

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> × N

API 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)

tsx
<Combobox name="x" options={…} placeholder="Choose one" />
Try it live
Open in play

Edit this component live in the bext playground. The PRISM + signals version is the bext-native idiom: fine-grained reactivity, no virtual DOM.

src/app/page.tsx 2 files · signals · runs in your browser
Pure PRISM + real bext signals: fine-grained, no re-render.