The listbox pattern is a form control. Also known as a "select", as it allows selection of one or more items from a list of options.
Like all form controls, the value (or values) make up the form data that is passed to the server. If you require similar behaviour, but without the need for form data, please consider the menu pattern instead.
HTML already gives us a native listbox control that is 100% accessible. However, it is difficult to style and it's options do not support inner HTML. Therefore the pattern we discuss here is primarily based upon a custom implementation that progressively enhances the native select element.
Do not call a listbox a "dropdown"! The term "dropdown" is ambiguous and could be confused with a menu, combobox or any other kind of overlay that "drops down".
You can take a look at the listbox pattern in action on our examples site.
- the pattern as a *whole*, comprising of a label, readonly combobox, flyout and options.
- the native html element
- the labelling element or text for the control
- combobox (readonly)
- used to cycle through options, and expands or collapses the overlay
- contains the full view of options
- each option available for selection
- boolean, indicating if multi-select is allowed
Listbox must belong inside of a form element, and that form element must have a submit button.
Listbox must support form-autofill behaviour of browser.
The combobox is the only element that receives keyboard focus.
The combobox must be set to readonly.
Selecting an option should not submit the form. It should only set the option state to selected.
Listbox can be set to multi-select but, if using the native select element, consider using checkboxes instead. This is because the keyboard controls to do multi-selection are not entirely easy or intuitive.
This section provides interaction design for keyboard, screen reader & pointing devices.
With focus on combobox, pressing UP and DOWN arrow keys will cycle through options.
With focus on combobox, pressing SPACEBAR will will toggle expanded state of flyout.
With focus on combobox, pressing ESCAPE key will collapse flyout.
With virtual cursor on combobox, screen reader should announce role, state and value.
With virtual cursor on combobox, pressing UP and DOWN arrow keys will announce newly selected option value.
Clicking or tapping combobox will toggle expanded state of flyout.
Clicking or tapping option in flyout will update combobox to that value.
<label for="car">Choose a car</label> <select id="car" name="car"> <option value="volvo">Volvo</option> <option value="saab">Saab</option> <option value="opel">Opel</option> <option value="audi">Audi</option> </select>
However, whilst the native HTML control can be styled to some extent in it's collapsed state, the expanded overlay state cannot.
This conundrum is the source of many custom solutions on the web. There are however, several pitfalls when it comes to accessibility.
Pitfall Number 1
Like all form controls, a listbox must support the autofill behaviour of the browser (see best practices above).
The only way to achieve this is to use a real
Pitfall Number 2
Perhaps a deeper rooted issue is that a custom styled listbox does not breed familiarity with users. Whilst not pretty, the native listbox is utilitarian; users find it both practical and familiar.
Despite the reservations mentioned above, we will guide you through an accessible custom listbox implementation.
Because of the issue described in pitfall 1 above, the only valid approach is progressive enhancement.
Let's go back to the
<select> tag markup we showed previously.
<select id="car" name="car"> <option value="volvo">Volvo</option> <option value="saab">Saab</option> <option value="opel">Opel</option> <option value="audi">Audi</option> </select>
This will be our model. It will be this element that gets updated when the browser autofills the form (i.e. one of the
<option> tags will receive the 'selected' property).
The model will be hidden from view (explained in the CSS section). We will create a new view using an ARIA listbox and options. Because we are no longer using a select tag, this markup allows us much greater flexibility in terms of CSS styling.
<input aria-owns="listbox1" role="combobox" type="text" readonly /> <ul id="listbox1" role="listbox"> <li role="option">Volvo</li> <li role="option">Saab</li> <li role="option">Opel</li> <li role="option">Audi</li> </ul>
Work in progress...