A listbox provides a way to select or reorder options in a predefined list and a selected option can then be made to perform a single action.
Listboxes have options that can be selected, reordered and made to perform an action
Options themselves cannot contain any interactive elements. For example, there cannot be a button, link or input within an option
Option names are flattened strings and should not contain any formatting, semantics or hierarchy that is a requirement for understanding the options meaning
Options cannot be required
Listboxes can be disabled, where each option is not selectable
Individual options can also be disabled
Listbox options can be grouped, with a label for each group
Single Select Listbox
A listbox should act as a single tab stop, in that a user should be able to press the tab key once to leave the control
Only one option should be focusable in the list. That option should be the most recently selected option. By default that is the first option in the list
Up and Down arrows: move focus and selection to the previous/next option
Arrow navigation should wrap within the list when at the first or last option, unless you are using lazy loading or infinite scrolling techniques
Recommended if more than 5 options:
Home and End should move focus to the first/last option
Type a character: focus moves to the next option that starts with the character
Type multiple characters in rapid succession: focus moves to the next option that starts with the string of characters
Horizontally Orientated Listbox
A horizontally orientated Listbox should follow all the same keyboard interaction as Single Select, with the addition of:
Right arrow: behaves the same as the Down arrow, both keys should navigate down the list
Left arrow: behaves the same as the Up arrow, both keys should navigate up the list
Multi Select Listbox
A Multi Select Listbox should follow all the same keyboard interaction as Single Select, with the addition of:
Shift + Up and Shift + Down: moves focus and selects additional, consecutive options
Control + Up and Control + Down: moves focus only
Control + A: selects/deselects all the options in the list
Control + Shift + Home/End: Selects the focused option and all options to the first/last option
Press space bar to toggle drag drop mode, use arrow keys to move selected elements.
A Re-orderable Listbox should follow all the same keyboard interaction as Single Select, and optionally the Multi Select Listboxes, with the addition of
Space: toggles Drag and Drop Mode:
If not in Drag and Drop Mode: space grabs the selected option(s)
If in Drag and Drop Mode: space drops the option(s) at their current position
Up and Down: if in Drag and Drop Mode, move the selected options within the list
All Listbox Variants
For demo purposes we use an Unordered List <ul /> as the root container element.
The root node needs role="listbox"
The listbox should be labelled. This can be with aria-label="Label name" or aria-labelledby, which points to a visible label
For demo purposes we use List Items <li /> as a Listbox option.
Element needs role="option"
Options must be direct descendants of the Listbox.
When using a markup pattern like ul[role="listbox"] > li > a[role="option"], where the anchor element is the clickable option, you should add role="presentation" to the li. This will cause assistive technology to only see a ul[role="listbox"] > a[role="option"] direct descendant relationship
aria-selected="true" is set on the option that is currently selected and in focus
Single select Listboxes only require aria-selected to be set on a single option. It should not be set on other options
tabindex=0 should be set on the only focusable option in the listbox and should move with user selection.
Horizontally Oriented Listbox
Requires all the same markup as related vertically oriented listbox, with the addition of:
The listbox element should have aria-orientation="horizontal" applied
Multi Select Listbox
Requires all the same markup as the single select, with the addition of:
The listbox element also needs aria-multiselectable="true"
Each option should now have aria-selected applied, which defaults to false. Only selected options should be set to true
Requires all the same markup as the single select listbox and optionally all of the multi select listbox markup, with the addition of:
Should have aria-describedby on the listbox set to the id of an element that contains instructions on how the drag and drop works (which can be visually hidden)
Should have an element separate from the unordered list:
with the attribute aria-live="assertive"
that contains the status of the elements being dragged. For example: "Element 1 grabbed. Current position 1 of 4", "Element 1 moved, new positon 2 of 4", and "Element 1 dropped, final position 2 of 4".
Recommended for Long Lists
If the complete list of options is not currently visible, but the size of the option set is known (for example, if using lazy loading) each list element needs:
aria-setsize set to the length of the list
aria-posinset set to the element's position in the list