Combobox

Type to filter, pick to commit. For lists too long to scan.

v1.0.0·Updated Jul 8, 2026 · 10:45
Live Demo — Fully Interactive
Type to filter — the match is highlighted, ↑↓ to move
Configuration
State
Placeholder
Ap
AppleApricot
<Combobox placeholder="Search fruit…" options={fruits} onSelect={fn} />
Behavior — The Engineering Contract
Prop / eventTypeNotes
optionsItem[]The full set to filter over
onSelect(item) => voidFires when an option is committed
filter(item, q) => booleanCustom matcher; defaults to substring
emptyStateReactNodeShown when nothing matches
↑ / ↓ · EnterMove the active option; Enter commits it
Esc · outside clickClose the list

Use a Combobox when the list is too long to scan but each pick is a known value. For free-text queries that return results use Search; for a short list use Dropdown.

Anatomy
Ap
AppleApricot
1InputFree text that filters as you type.
2MatchThe typed substring, highlighted warm.
3Active rowKeyboard cursor; Enter commits it.
Do's and Don'ts
✓ Do
MangoMandarin

Highlight the match so the reader sees why each result is here.

✕ Don't
MangoMandarinMelon

Don't just dump the whole list unfiltered. Then it is only a Dropdown.

✓ Do
No fruit matches “xyz”.

Give the no-match case an honest, specific message.

✕ Don't

Don't leave an empty box open. Silence reads as broken.

In context: Examples
A · Country picker
Search 190 countries…

Long lists that a plain Dropdown would drown in.

B · Assignee
ada@team.comadam@team.com

Assigning people by typing part of a name or email.

C · Tag entry
des

Choosing from a controlled vocabulary of tags or labels.

Measurements & Tokens
TokenValueRole
--combo-match#FF9D45Highlighted substring, weight 600
--combo-active#1E1F25Keyboard-active row
--menu-max-h244pxListbox scrolls past this
--menu-bg#141519Results panel
--empty-color#767B87Empty-state text
--field-focusrgba(255,122,0,.14)Warm focus ring on the input
Code
<div class="o-combo">
  <input class="o-input" role="combobox" aria-expanded="true"
         aria-autocomplete="list" placeholder="Search fruit…" />
  <div class="o-menu" role="listbox">
    <button role="option" class="o-menu__opt is-active">
      <b class="o-combo__match">Ap</b>ple
    </button>
    <button role="option" class="o-menu__opt"><b class="o-combo__match">Ap</b>ricot</button>
  </div>
</div>