Listbox
A “combobox” is a role="combobox"
that does allow editing its input. Currently, the only allowed combobox is one which has a “listbox” popup. Almost all elements except for the “anchored region” are in the light DOM for accessibility reasons.
The currently hovered / focus <role-option>
has [aria-current="true"]
The currently selected <role-option>
has [aria-selected="true"]
Description
This is a listbox! It supports:
- Multi-select
- Typeahead
- Managed focus via aria-activedescendant
- And pretty much everything in the W3C listbox spec
It follows the spec for a listbox described here: https://www.w3.org/WAI/ARIA/apg/patterns/listbox/
Keyboard Support
Single Select
When a single-select listbox receives focus:
- If none of the options are selected before the listbox receives focus, the first option does not receive focus. The first option is not automatically selected.
-
If an option is selected before the listbox receives focus, focus is set on the selected option.
- Down Arrow: Moves focus to the next option. Selection moves with focus.
- Up Arrow: Moves focus to the previous option. Selection moves with focus.
- Home: Moves focus to first option. Selection moves with focus.
- End: Moves focus to last option. Selection moves with focus.
Multi Select
When a multi-select listbox receives focus:
- If none of the options are selected before the listbox receives focus, focus is set on the first option and there is no automatic change in the selection state.
- If one or more options are selected before the listbox receives focus, focus is set on the first option in the list that is selected.
The keyboard shortcuts supported in a single select listbox are also supported in a multi-select listbox.
The Control key and Command behave the same on MacOS.
- Space: changes the selection state of the focused option.
- Shift + Down Arrow: Moves focus to and toggles the selected state of the next option. Also works like a range.
- Shift + Up Arrow: Moves focus to and toggles the selected state of the previous option. Also works like a range.
- Shift + Space: Selects contiguous items from the most recently selected item to the focused item.
- Control + Shift + Home: Selects the focused option and all options up to the first option. Optionally, moves focus to the first option.
- Control + Shift + End: Selects the focused option and all options down to the last option. Optionally, moves focus to the last option.
- Control + A: Selects all options in the list. Optionally, if all options are selected, it may also unselect all options.
Additional support
Shift + Click - Selects a range from the most recently selected option to the currently clicked option. Holding shift causes the range starting point to not reset.
Examples
Single Select listbox
Single Select listbox with wrapping on first / last items
Single Select listbox with groups
Multi Select Examples
Multi-Select listbox
Multi Select listbox with groups
Pre-selected options
API Reference
Imports
<!-- Auto registers as <role-listbox> -->
<script type="module" src="https://cdn.jsdelivr.net/npm/role-components/exports/listbox/listbox-register.js"></script>
<script type="module">
// Auto registers as <role-listbox>
import "https://cdn.jsdelivr.net/npm/role-components/exports/listbox/listbox-register.js"
// Manual Register
import RoleListbox from "https://cdn.jsdelivr.net/npm/role-components/exports/listbox/listbox.js"
RoleListbox.define()
// => Registers as <role-listbox>
</script>
// Auto registers as <role-listbox>
import "role-components/exports/listbox/listbox-register.js"
// Manual Register
import RoleListbox "role-components/exports/listbox/listbox.js"
RoleListbox.define()
// => Registers as <role-listbox>
Attributes
Name | Description | Reflects | Type | Default |
---|---|---|---|---|
[Attribute]
wrap-selection
[Property] wrapSelection
|
-
|
|
boolean
|
false
|
[Attribute + Property]
autocomplete
|
-
|
|
string
|
"off"
|
[Attribute + Property]
multiple
|
-
|
|
boolean
|
false
|
[Attribute]
tabindex
[Property] tabIndex
|
-
|
|
number
|
0
|
[Attribute + Property]
label
|
-
|
|
string
|
""
|
[Attribute]
search-buffer-delay
[Property] searchBufferDelay
|
Delay before the search buffer returns to an empty string |
|
number
|
1000
|
[Attribute + Property]
length
|
-
|
|
-
|
-
|
Functions
Name | Description | Parameters |
---|---|---|
formResetCallback()
|
-
|
-
|
setFocus()
|
-
|
option: HTMLElement
|
removeFocus()
|
-
|
option: HTMLElement
|
handleOptionClick()
|
-
|
evt: PointerEvent
|
handleOptionHover()
|
-
|
evt: Event
|
handleKeyUp()
|
Reset range when shiftKey goes up |
evt: KeyboardEvent
|
handleKeyDown()
|
-
|
evt: KeyboardEvent
|
selectFromClosestSelectedToCurrent()
|
Finds the closest selected option prior to the current option |
-
|
selectFromRangeStartToCurrent()
|
-
|
-
|
selectRange()
|
Selects all options in a range and deselects all options not in the range |
{ from, to }, options: Range
|
selectFromStartToCurrent()
|
-
|
startIndex: number
|
selectFromCurrentToEnd()
|
-
|
endIndex: number
|
focusElementFromSearchBuffer()
|
-
|
-
|
select()
|
-
|
element: HTMLElement
|
deselect()
|
-
|
element: HTMLElement
|
selectAll()
|
Mark every element with [aria-selected=”true”] |
-
|
deselectAll()
|
Mark every element with [aria-selected=”false”] |
-
|
toggleSelected()
|
-
|
selectedElement: HTMLElement
|
focusCurrent()
|
-
|
-
|
focusAt()
|
-
|
index: number
|
focusNext()
|
-
|
-
|
focusPrevious()
|
-
|
-
|
focusFirst()
|
-
|
-
|
focusLast()
|
-
|
-
|
scrollOptionIntoView()
|
-
|
selectedOption: HTMLElement
|
handleFocusIn()
|
-
|
_evt: FocusEvent
|
isSelected()
|
-
|
el: HTMLElement
|
updateOptions()
|
-
|
-
|
assignRandomId()
|
Users dont always provide ids on elements, and we need to make sure the id isn’t already taken. |
el: HTMLElement
|
debounce()
|
-
|
callback: (...args: any[]) => any, options: { key: any, wait: number }
|