Skip to main content
Cayuse Design System Lato · 4pt grid · WCAG 2.1 AA

Components · Inputs

Combobox

A text field that filters a list as the user types. The right control when the list is too long to scan — departments, sponsors, personnel — and the basis of the suite’s search-assisted entry.

Figma source: Combobox ↗

Examples

Combobox with results
html
<div class="cds-field">
  <label class="cds-field__label" for="sponsor">Sponsor</label>
  <div class="cds-input-group">
    <span class="cds-input-group__icon fa fa-search" aria-hidden="true"></span>
    <input class="cds-input" id="sponsor" type="text"
           role="combobox" aria-expanded="false" aria-controls="sponsor-list"
           aria-autocomplete="list">
  </div>
  <div id="sponsor-list" role="listbox" aria-label="Sponsor results">…</div>
</div>
Multiple selection, using Data Pills
R. Alvarez M. Chen
html
<!-- Selected values become removable Data Pills above the field -->
<span class="cds-data-pill">R. Alvarez
  <button class="cds-data-pill__remove" type="button" aria-label="Remove R. Alvarez">✕</button>
</span>

Figma properties

PropertyValuesNotes
StateDefault · Focus · Disabled · Error · ResultsResults is the open state with the filtered list shown.
Text TypeDefault · Blank · Entered · Single Selection · Multiple SelectMulti-select renders selected values as Data Pills.
Icon?booleanLeading search glyph.
The placeholder-and-error rule, straight from the Figma annotations

The Figma file states it twice, for Text Input and again for Combobox: “No variant for error state with placeholder. Errors would only occur on inputs that have already had text.” and “No variant for focus state with placeholder. If user focuses on inputs, placeholder text is removed.”

That is correct behaviour, not a gap in the component set. A placeholder is visible only while the field is empty and unfocused; the moment it is focused or filled, the placeholder is gone, so a placeholder can never coexist with a focus ring or an error message.

Behaviour, from the Figma annotations

The Combobox page carries more interaction annotation than any other component in the file. The behaviour it specifies:

  • The user clicks or tabs into the text area and begins typing; results filter as they type.
  • Results are announced as a list — “Result A, Result AB…” — and the user moves through them with arrow keys.
  • The selected result is announced on selection.
  • When a result and its secondary information do not fit the dropdown width, the row wraps to a stacked layout rather than truncating.
Announce the number of results, not just the results

The annotations describe reading out the result rows. Add a live region that first announces how many there are — “3 results available” — so a screen-reader user knows whether to start arrowing through the list or refine the query. Without it, the only way to discover that a search returned 200 rows is to walk them.

Use aria-live="polite" and debounce it, so it speaks when typing pauses rather than on every keystroke.

Usage

When to use it

  • Use when the list is long enough that typing beats scrolling — roughly 15 options and up.
  • Highlight the matched substring in each result, as the examples above do.
  • Show secondary data where it disambiguates similar entries — two people with the same surname, two sponsors with similar names.
  • Let the user clear the field in one action.

When not to use it

  • Do not use for short, stable lists — a Select is simpler and needs no JavaScript.
  • Do not require an exact match; filter on substrings anywhere in the string, not just the start.
  • Do not clear what the user typed when the list returns nothing — tell them there are no matches and leave the text.
  • Do not auto-select the first result on blur; users lose control of what was chosen.

Accessibility

  • Implement the ARIA combobox pattern in full: role="combobox" on the input, aria-expanded, aria-controls pointing at the listbox, and aria-activedescendant tracking the focused option.
  • Keyboard: Down opens and moves into the list, Up/Down navigate, Enter selects, Escape closes and returns focus to the input without changing the value.
  • Keep DOM focus on the input while arrowing through options — move aria-activedescendant, not focus itself.
  • In multi-select, each pill’s remove button needs its own label naming the value it removes.

Tokens consumed

TokenApplied toResolves to
--input-backgroundField fill--color-white
--input-borderResting border--color-gray-400 → #888c8c
--input-textEntered value--color-black → #111111
--input-focus-borderFocus ring--focus-ring → #44a3db ⚠
--input-error-backgroundFill in error--color-red-100
--input-error-borderBorder in error--color-red-500
--input-disabled-backgroundFill when disabled--color-gray-100
--input-disabled-textValue when disabled--disabled-text → #888c8c
--input-labelLabel--color-black
--input-requiredRequired asterisk--color-red-500
--input-captionHelp text and placeholder--color-gray-500
--input-error-captionError message--color-red-500
--menu-backgroundResults surface--color-white
--menu-hoverResult hover--color-gray-200
--menu-activeHighlighted result--color-blue-100