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:

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:

Multi Select

When a multi-select listbox receives focus:

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.

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

Script
HTML
<!-- Auto registers as <role-listbox> -->
<script type="module" src="https://cdn.jsdelivr.net/npm/role-components/exports/listbox/listbox-register.js"></script>
CDN
HTML
<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>
Bundler
JavaScript
// 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 }