Skip to content

Combobox · Combobox menu

Combobox — a Select you can type into: the trigger opens a list with a search field, the list narrows as you type, one row is chosen.

Beta · Forms · packages/css/src/components/combobox.css

.pui-combobox (Select’s trigger with chevrons-up-down and an <input> as __value) · .pui-combobox-menu (__search __items __empty, rows are .pui-select-item).

Combobox · Combobox menu — every size and every stateOpen in the workshop

Sizes across, states down.

  • Placeholder and Value, Has placeholder / Has value — the value is the chosen row’s label, or the query while typing
  • Has prefix + Prefix, Has icon leading + Icon leading — Select’s, unchanged
  • Three sizes 28 / 36 / 44, five states — Select’s exactly; open is the focus state with the menu under it (the example)
  • The list is Combobox menu — the search row, the rows, the empty row

Use when one choice from a list long enough to search — accounts, offers, people, countries — roughly twenty or more, or any list the user knows by name.

Do not use when the list is short (Select); the user may type a value that is not in the list (Input, with suggestions later); several may be chosen (a multi-select Combobox is a later row); the control runs actions (Dropdown menu).

Relates to Select, Select menu, Select item, Input, Field, Combobox menu, Dropdown menu.

Anti-patterns a combobox with five options · a search field that filters nothing (that is Input group) · a value that is not one of the rows · a chevron-down on it (that says Select) · a fill changed on the instance.

Keywords: combobox, autocomplete, searchable select, typeahead, react-select

Figma — page Combobox: Combobox (15 variants) · Combobox menu (1 variants)

shadcn: combobox

The class, the parts, and nothing that is not in the package. The same block opens combobox.css.

<div class="pui-combobox">
<input class="pui-combobox__value" role="combobox" aria-expanded="false" aria-controls="menu-id" aria-autocomplete="list" aria-label="Account" placeholder="Pick an account">
(ARIA 1.2: the role, the expanded state and the name sit on the input, not on the box, axe)
<span class="pui-icon pui-combobox__chevron">…chevrons-up-down…</span></div>
<div class="pui-combobox-menu">
<div class="pui-combobox-menu__search"><span class="pui-icon">…search…</span><input aria-label="Search accounts" placeholder="Search…"></div>
<div class="pui-combobox-menu__items" role="listbox"> …pui-select-item… </div>
<div class="pui-combobox-menu__empty">No results.</div></div>

Rule — one row highlighted at a time — the first visible one when the list opens (data-highlighted).

Every number here is measured on the rendered component: contrast (npm run contrast:render), the focus ring (npm run focus) and the keyboard (npm run keyboard). The floors are principle 12’s.

ink on ground reads floor the matrix calls it
#544d4d on #ffffff 8.24 4.5 text.muted on surface.page (promised) ok
#0b0202 on #f2f2f2 18.32 4.5 text.default on surface.sunken (promised) ok
#0b0202 on #ffffff 20.51 4.5 text.default on surface.page (promised) ok

3 distinct pair(s) rendered, 0 that axe calls a violation.

primitive on the indicator over the change
Combobox menu search surface/page shadow-inset #6a66e4 2 px #ffffff 4.53 ok

4 of 4 focus stop(s) in this block meet WCAG 2.4.13 on screen — the same crop screenshotted focused and unfocused, and the difference measured; 1 stop(s) the Tab key does not reach or that the specimen draws in a state that only exists while focused.

role tab stops what the pattern requires
listbox .pui-combobox-menu__items 0 0 — its trigger holds it ok
combobox .pui-combobox__value 0 — —
combobox .pui-combobox__value 0 — —
combobox .pui-combobox__value 0 — —

What the consumer’s script owes. the input holds the tab stop and carries aria-expanded, aria-controls and, while open, aria-activedescendant; every option in the popup takes tabindex=“-1”. The script owes Down to open and move, Up / Down inside, Enter to select, Escape to close then clear.

Tab order across the whole library is document order over 344 stops, and Shift+Tab is its exact reverse — no keyboard trap anywhere (WCAG 2.1.2).

Pepper UI v1.5.0

The Mobupps design system. 386 tokens, 88 components, 65 pages in the workshop — every page of this site generated from the repository, so nothing here is typed twice.