24Combobox
Type-ahead over a known list — a course, a tag, an org. A <select> cannot be searched and a bare text input cannot be trusted; this is the third thing.
Use it for
- A list too long to scan but closed enough to validate against
- Where the reader knows roughly what they want and can type it faster than they can find it
Not for
- Under about seven options — use a Select; searching five things is friction, not help
- Free text — if any value is allowed it is an Input, not a combobox
- Multi-select — use Tag input
Open, filtering
The matched run is emphasised inside each option so the reader can see WHY a row matched.
- Apex fundamentals
- Apex triggers in depth
- Testing Apex
markup
<div class="ns-combobox">
<input class="ns-input" type="text" role="combobox" aria-expanded="true" aria-controls="cb-list" aria-autocomplete="list" value="apex" autocomplete="off">
<ul class="ns-combobox__list" id="cb-list" role="listbox">
<li class="ns-combobox__option" role="option" aria-selected="true"><span><span class="ns-combobox__match">Apex</span> fundamentals</span><span class="ns-combobox__meta">12 lessons</span></li>
<li class="ns-combobox__option" role="option" aria-selected="false"><span><span class="ns-combobox__match">Apex</span> triggers in depth</span><span class="ns-combobox__meta">8 lessons</span></li>
<li class="ns-combobox__option" role="option" aria-selected="false"><span>Testing <span class="ns-combobox__match">Apex</span></span><span class="ns-combobox__meta">6 lessons</span></li>
</ul>
</div>No matches
Say what was searched. “No results” alone leaves the reader unsure whether the query or the data is wrong.
- No course matches vlocity.
markup
<div class="ns-combobox">
<input class="ns-input" type="text" role="combobox" aria-expanded="true" aria-controls="cb-empty" value="vlocity" autocomplete="off">
<ul class="ns-combobox__list" id="cb-empty" role="listbox">
<li class="ns-combobox__empty" role="option" aria-selected="false">No course matches <strong>vlocity</strong>.</li>
</ul>
</div>Accessibility contract
- A real <input>, so autofill, IME, mobile keyboards and paste all behave
- aria-expanded on the input; role=listbox / role=option on the list
- aria-activedescendant points at the highlighted option, so the highlight is never a class the assistive layer cannot see
- Without JS the input still submits its value — a search box that types beats a combobox that does nothing