Listbox
Accessible, unstyled Listbox with active-descendant focus and typed selection.
| Package | @vizejs/ui/listbox |
| Maturity | stable |
| Own the source | vize lib pull listbox |
| Requires | collection, composite-navigation, context, controllable-state, id, typeahead |
| Aliases | listbox, option list, single select, multi select |
| Covers | WAI-ARIA listbox pattern, React Aria ListBox, Ariakit Select, Reka UI Listbox |
Minimal setup
Use a Vue 3.5+ project with Vue SFC compilation configured (see Vite+ integration).
vp install @vizejs/ui
Add the public import below to <script setup lang="ts">. Components provide behavior without styles; the preview uses optional Paper styles.
import { Listbox, ListboxItem } from "@vizejs/ui/listbox";
Or copy the source into your project with vize lib pull listbox (see Source Distribution).
Try it
This is the basic example maintained with the component source, using the public package imports. The preview adds the optional Paper styles.
Open the interactive example · Styling these components
Copy the example
<!-- Single-select listbox bound with v-model, labelled by a heading, with one disabled option. -->
<script setup lang="ts">
import { ref, useId } from "vue";
import { Listbox, ListboxItem, type ListboxValue } from "@vizejs/ui/listbox";
const region = ref<ListboxValue>("eu-west");
const labelId = useId();
const regions = [
{ value: "us-east", label: "US East (Virginia)", disabled: false },
{ value: "eu-west", label: "EU West (Ireland)", disabled: false },
{ value: "ap-south", label: "Asia Pacific (Mumbai)", disabled: true },
];
</script>
<template>
<div>
<h3 :id="labelId">Deployment region</h3>
<Listbox v-model="region" :aria-labelledby="labelId">
<ListboxItem
v-for="item in regions"
:key="item.value"
:value="item.value"
:disabled="item.disabled"
>
{{ item.label }}
</ListboxItem>
</Listbox>
<output>Selected: {{ region ?? "none" }}</output>
</div>
</template>
API
Listbox
Source: src/families/selection/listbox/listbox.vue
Props
| Prop | Type | Default | Description |
|---|---|---|---|
id |
string | null |
undefined |
Consumer-owned listbox id. null and undefined select a deterministic fallback. |
modelValue |
ListboxValue |
undefined |
Controlled selected value. undefined selects uncontrolled behavior. |
defaultValue |
ListboxValue |
undefined |
Initial value for uncontrolled use and the value restored by reset. |
disabled |
boolean |
false |
Disable every option and remove the listbox from sequential focus order. |
required |
boolean |
false |
Mark the listbox as required for accessibility and validation summaries. |
selectionMode |
ListboxSelectionMode |
"single" |
Select one option or a set of options. |
orientation |
ListboxOrientation |
"vertical" |
Directional layout hint used by arrow-key navigation. |
direction |
ListboxDirection |
"ltr" |
Reading direction used by horizontal arrow-key navigation. |
loop |
boolean |
false |
Wrap arrow-key navigation at collection boundaries. |
typeahead |
boolean |
true |
Enable locale-aware typeahead over option text. |
typeaheadTimeout |
number |
500 |
Idle time before buffered typeahead starts a new query. |
ariaLabel |
string |
undefined |
Accessible name when no visible label or aria-labelledby supplies one. |
ariaLabelledby |
string |
undefined |
Space-separated ids that label the listbox. |
ariaDescribedby |
string |
undefined |
Space-separated ids that describe the listbox. |
ariaErrormessage |
string |
undefined |
Id of the validation error message used while invalid. |
ariaInvalid |
ListboxAriaInvalid |
false |
Invalid state announced to assistive technology. |
Events
| Event | Payload | Description |
|---|---|---|
update:modelValue |
[value: ListboxValue] |
Fired when the selected value requests a new controlled value. |
change |
[value: ListboxValue, previous: ListboxValue, nativeEvent: Event] |
Fired after user selection requests a distinct Listbox value. |
Slots
| Slot | Slot props | Description |
|---|---|---|
default |
ListboxSlotState |
Compound ListboxItem options. Receives current selection and focus state. |
empty |
ListboxSlotState |
Empty collection fallback rendered when no options are registered. |
Exposed
| Member | Type | Description |
|---|---|---|
value |
ListboxValue |
Current selected value, or an array when selectionMode is "multiple". |
selectedValues |
readonly string[] |
Selected values as a stable readonly array. |
activeValue |
string | null |
Current active option value, or null when no option is navigable. |
disabled |
boolean |
Whether every item is disabled by the listbox. |
required |
boolean |
Whether the listbox participates in required validation semantics. |
invalid |
boolean |
Whether the listbox is currently marked invalid. |
selectionMode |
ListboxSelectionMode |
Whether single or multiple selection is active. |
orientation |
ListboxOrientation |
Directional layout hint for ARIA and consumer-owned styles. |
direction |
ListboxDirection |
Reading direction used by horizontal keyboard navigation. |
state |
ListboxState |
Stable state token for styling and tests. |
element |
HTMLDivElement | null |
Rendered listbox element. |
id |
string |
Root-owned id for the listbox. |
focus |
(options?: FocusOptions) => void |
Move DOM focus to the listbox focus owner. |
navigate |
( command: "first" | "last" | "next" | "page-next" | "page-previous" | "previous", nativeEvent?: Event | null, ) => string | null |
Move the active option by command and report the resulting option value. |
setActiveValue |
(value: string | null) => boolean |
Request an active option update and report whether it changed. |
setValue |
(value: ListboxValue) => boolean |
Request a selected value update and report whether it differs. |
selectValue |
(value: string, nativeEvent?: Event | null) => boolean |
Select an option value and report whether the selection changed. |
toggleValue |
(value: string, nativeEvent?: Event | null) => boolean |
Toggle an option value in the current selection model. |
clear |
() => boolean |
Clear the current selection and report whether it changed. |
reset |
() => boolean |
Restore the current default value and report whether it changed. |
ListboxItem
Source: src/families/selection/listbox/listbox-item.vue
Props
| Prop | Type | Default | Description |
|---|---|---|---|
id |
string | null |
undefined |
Consumer-owned option id. null and undefined select a deterministic fallback. |
value (required) |
string |
required |
Stable option value used for selection and collection identity. |
disabled |
boolean |
false |
Disable this option while preserving the rest of the listbox. |
textValue |
string | null |
undefined |
Explicit typeahead text. null and undefined select accessible DOM text extraction. |
order |
number |
undefined |
Deterministic order for virtualized or server-only options. |
ariaLabel |
string |
undefined |
Accessible name when no option text supplies one. |
ariaLabelledby |
string |
undefined |
Space-separated ids that label this option. |
ariaDescribedby |
string |
undefined |
Space-separated ids that describe this option. |
Slots
| Slot | Slot props | Description |
|---|---|---|
default |
ListboxItemSlotState |
Option content. Receives active, selected, disabled, and mode state. |
indicator |
ListboxItemSlotState |
Optional selection indicator controlled by the consumer. |
Exposed
| Member | Type | Description |
|---|---|---|
value |
string |
Item value used for selection and active-descendant ownership. |
active |
boolean |
Whether this item is the active option. |
selected |
boolean |
Whether this item is currently selected. |
disabled |
boolean |
Whether this item is disabled by itself or the listbox. |
selectionMode |
ListboxSelectionMode |
Whether single or multiple selection is active. |
state |
ListboxItemState |
Stable state token for styling and tests. |
element |
HTMLDivElement | null |
Rendered option element. |
focus |
(options?: FocusOptions) => void |
Move active-descendant focus to this item through the root listbox. |
select |
() => boolean |
Select this item and report whether the selection changed. |
Behavior
Contract
Listbox is a headless compound primitive for option selection. listbox.vue
renders role="listbox" and owns DOM focus through aria-activedescendant.
listbox-item.vue renders role="option" and registers with the local
collection registry for ordering, typeahead, and disabled-state recovery.
Styling is owned by consumers through parts, slots, CSS, and data attributes.
Public Surface
| Surface | Contract |
|---|---|
Listbox props |
id, modelValue, defaultValue, disabled, required, selectionMode, orientation, direction, loop, typeahead, typeaheadTimeout, ariaLabel, ariaLabelledby, ariaDescribedby, ariaErrormessage, ariaInvalid |
Listbox emits |
update:modelValue(value), change(value, previous, nativeEvent) |
Listbox slots |
default(state), empty(state) |
Listbox expose |
element, id, value, selectedValues, activeValue, disabled, required, invalid, selectionMode, orientation, direction, state, focus, navigate, setActiveValue, setValue, selectValue, toggleValue, clear, reset |
ListboxItem props |
id, value, disabled, textValue, order, ariaLabel, ariaLabelledby, ariaDescribedby |
ListboxItem slots |
default(state), indicator(state) |
ListboxItem expose |
element, value, active, selected, disabled, selectionMode, state, focus, select |
| Parts | root, item |
| Root data attributes | data-vize-ui="listbox", data-state, data-disabled, data-required, data-invalid, data-orientation, data-selection-mode, data-selection-count, data-value |
| Item data attributes | data-vize-ui="listbox-item", data-state, data-value, data-selected, data-active, data-disabled, data-selection-mode |
Normative Behavior
| Input | Single Selection | Multiple Selection |
|---|---|---|
| Tab | Moves focus to the listbox when enabled. Disabled roots are skipped. | Same as single. |
| Arrow Down / Arrow Right | Moves the active option to the next navigable item for matching orientation. | Same as single. |
| Arrow Up / Arrow Left | Moves the active option to the previous navigable item for matching orientation. | Same as single. |
| Home / End | Moves the active option to the first or last navigable item. | Same as single. |
| Printable grapheme | Runs locale-aware typeahead over option text and moves only active state. | Same as single. |
| Enter / Space | Selects the active option. | Toggles the active option. |
| Pointer click | Selects the clicked enabled option. | Toggles the clicked enabled option. |
| Disabled item | Is exposed with aria-disabled, omitted from active navigation and typeahead, and cannot change selection. |
Same as single. |
| Controlled value | Emits the requested value and waits for the parent to accept it. | Same as single with readonly arrays. |
| Uncontrolled value | Mutates internal state, emits the requested value, and can reset to defaultValue. |
Same as single with readonly arrays. |
SSR
Generated root and option ids use the deterministic-id primitive. Isolated SSR requests must produce byte-identical markup for the same tree, and hydration must not replace the rendered root or option ids.