Listbox
A listbox presents a list of selectable options using the ARIA listbox role, with full keyboard navigation support. It is used when users need to select one or more items from a visible list, as opposed to a dropdown select. Common use cases include settings panels, filter selections, multi-select interfaces, and any scenario where all options should be visible simultaneously.
The component manages focus movement between options via arrow keys, with Home and End keys to jump to the first and last items. The consumer provides option elements as children and handles selection state externally.
Implementation Notes
- Renders a
<div>withrole="listbox"and an accessible label. - Uses reactive state to track the
listRefelement reference for querying child options. - Keyboard navigation queries all child elements with
[role='option']to build the navigable item list. - Arrow keys wrap around: pressing ArrowDown on the last item moves focus to the first, and vice versa.
- Home and End keys jump to the first and last option respectively.
- Spreads
restPropsonto the container for consumer customization.
Props
label: string (required) -- accessible name applied viaaria-label.children: slot (required) -- option elements to render inside the listbox (should haverole="option"andtabindex="-1")....restProps: unknown -- additional attributes spread onto the container<div>.
Usage
Priority level selector:
<Listbox label="Select priority">
<div role="option" tabindex="-1" aria-selected="true">High</div>
<div role="option" tabindex="-1" aria-selected="false">Medium</div>
<div role="option" tabindex="-1" aria-selected="false">Low</div>
</Listbox>
Department filter in a settings panel:
<Listbox label="Filter by department">
{#each departments as dept}
<div
role="option"
tabindex="-1"
aria-selected={selectedDept === dept}
onclick={() => selectedDept = dept}
>
{dept}
</div>
{/each}
</Listbox>
Theme selection with visible options:
<Listbox label="Choose a theme">
<div role="option" tabindex="-1" aria-selected="false">Light</div>
<div role="option" tabindex="-1" aria-selected="false">Dark</div>
<div role="option" tabindex="-1" aria-selected="true">System</div>
</Listbox>
Keyboard Interactions
- ArrowDown: Moves focus to the next option, wrapping to the first option from the last.
- ArrowUp: Moves focus to the previous option, wrapping to the last option from the first.
- Home: Moves focus to the first option.
- End: Moves focus to the last option.
ARIA
role="listbox"-- identifies the container as a listbox widget for selecting from a list of options.aria-label-- provides an accessible name describing the purpose of the listbox.- Child elements should use
role="option"and optionallyaria-selectedto indicate selection state.
When to Use
- Use Listbox when users need to select one or more items from a visible list of options, such as filter panels or settings.
- Use Listbox instead of a Select when all options should be visible simultaneously without opening a dropdown.
- Use Listbox for preference or settings panels where the user chooses from a short to medium list.
- Use Listbox for multi-select interfaces where users need to see all available options at once.
When Not to Use
- Do not use Listbox for dropdown selection where space is limited -- use Select or Combobox instead.
- Do not use Listbox for checkable items with independent on/off states -- use CheckboxGroup instead.
- Do not use Listbox for very long option lists that benefit from type-ahead filtering -- use Combobox instead.
Headless
This headless component provides the ARIA listbox role, keyboard navigation (arrow keys, Home, End with wrapping), and focus management for child option elements. The consumer provides all visual styling, including option appearance, selected-state highlighting, scrolling behavior, and focus indicators.
Styles
The consumer provides all CSS styling. The component renders with a .listbox class for targeting. No default styles are included — this is a fully headless component.
Testing
- Verify the component renders a
<div>element with classlistbox - Verify role="listbox"` -- identifies the container as a listbox widget for selecting from a list of options.
- Verify aria-label` -- provides an accessible name describing the purpose of the listbox.
- Verify Child elements should use
role="option"and optionallyaria-selectedto indicate selection state. - Verify keyboard interactions work correctly
- Verify pass-through attributes are applied
Advice
- Designers: Provide clear visual distinction for the selected and focused option states, using both color and a non-color indicator to support color-blind users.
- Developers: Ensure each child option uses
role="option"withtabindex="-1"and managearia-selectedon options to reflect the current selection state.
Related components
select— a dropdown select element for choosing one optioncombobox— a text input combined with a dropdown list for filtering optionsoption— an option element within a select dropdown
References
- WAI-ARIA Listbox Pattern: https://www.w3.org/WAI/ARIA/apg/patterns/listbox/