Components

Listbox

Headless listbox primitives for choosing one or more options from a visible option list.

When to Use

Use Listbox when people need to choose from a list that stays visible, such as selecting team members or assigning several tags. Use Select when the choices should open from a compact trigger, Menu for commands such as Rename or Delete, and native radio buttons or checkboxes when every choice should be a separate form control.

Features

  • Implements WAI-ARIA listbox and option roles.
  • Supports single and multiple selection.
  • Supports controlled and uncontrolled values.
  • Supports option groups and labels.
  • Supports roving active option with aria-activedescendant.
  • Supports typeahead, Home/End, arrow navigation, disabled options, form submission, and Field context.

Import

import { Listbox } from "@flowstack-ui/atom";

Anatomy

<Listbox.Root>
  <Listbox.Group>
    <Listbox.Label />
    <Listbox.Option>
      <Listbox.OptionText />
    </Listbox.Option>
  </Listbox.Group>
</Listbox.Root>

API Reference

Root

Renders the focusable listbox container, owns selection and highlight state, and submits selected values through hidden inputs when name is provided.

PropTypeDefault
childrenReactNode-
valuestring | string[] | null-
defaultValuestring | string[] | nullnull or []
onValueChange(value) => void-
multiplebooleanfalse
disabledbooleanField value
readOnlybooleanField value
requiredbooleanField value
invalidbooleanField value
orientation"vertical" | "horizontal""vertical"
loopbooleantrue
namestring-
formstring-
asChildbooleanfalse
renderRenderProp-
ARIA attributeValues
aria-activedescendantID of the highlighted option
aria-describedbyNative value or inherited Field description IDs
aria-disabledPresent when disabled
aria-invalidPresent when invalid
aria-multiselectablePresent in multiple-selection mode
aria-orientation"vertical" | "horizontal"
aria-readonlyPresent when read only
aria-requiredPresent when required
Data attributeValues
[data-slot]"listbox"
[data-multiple]Present when multiple
[data-filled]Present when one or more values are selected
[data-highlighted]Present while an option is highlighted
[data-disabled]Present when disabled
[data-readonly]Present when read only
[data-invalid]Present when invalid

Option

Renders one option, registers it for keyboard movement and typeahead, and updates the root selection when it is clicked or activated from the keyboard.

PropTypeDefault
childrenReactNode-
valuestringrequired
labelstring-
disabledbooleanfalse
asChildbooleanfalse
renderRenderProp-
ARIA attributeValues
aria-selectedWhether the option is selected
aria-disabledPresent when the option or root is disabled
aria-labelledbyGenerated OptionText ID when that part is mounted
Data attributeValues
[data-slot]"listbox-option"
[data-value]option value
[data-state]"checked" | "unchecked"
[data-selected]Present when selected
[data-highlighted]Present when active
[data-disabled]Present when disabled

OptionText

Provides the option's accessible text and registers its rendered text for typeahead. Use it when the option contains more than a simple text child.

PropTypeDefault
childrenReactNode-
asChildbooleanfalse
renderRenderProp-
Data attributeValues
[data-slot]"listbox-option-text"

Group

Renders a group inside the listbox and connects it to its nested Label.

PropTypeDefault
childrenReactNode-
asChildbooleanfalse
renderRenderProp-
ARIA attributeValues
aria-labelledbyGenerated ID of the nested Label
Data attributeValues
[data-slot]"listbox-group"

Label

Names the surrounding Group and provides the ID used by its aria-labelledby relationship.

PropTypeDefault
childrenReactNode-
idstringgenerated
asChildbooleanfalse
renderRenderProp-
Data attributeValues
[data-slot]"listbox-label"

Advanced compound components can use useListboxContext, useListboxOptionContext, and useListboxGroupContext. Their matching context providers and context value types are also public exports.

Examples

Single Selection

import { Listbox } from "@flowstack-ui/atom";

export function SizeListbox() {
  return (
    <Listbox.Root defaultValue="small" aria-label="Size">
      <Listbox.Option value="small">Small</Listbox.Option>
      <Listbox.Option value="large">Large</Listbox.Option>
    </Listbox.Root>
  );
}

Multiple Selection

import { Listbox } from "@flowstack-ui/atom";

export function ColorListbox() {
  return (
    <Listbox.Root
      multiple
      defaultValue={["red"]}
      name="colors"
      aria-label="Colors"
    >
      <Listbox.Group>
        <Listbox.Label>Available colors</Listbox.Label>
        <Listbox.Option value="red">
          <Listbox.OptionText>Red</Listbox.OptionText>
        </Listbox.Option>
        <Listbox.Option value="blue">
          <Listbox.OptionText>Blue</Listbox.OptionText>
        </Listbox.Option>
      </Listbox.Group>
    </Listbox.Root>
  );
}

Accessibility

Follows the WAI-ARIA listbox pattern. The root keeps DOM focus and exposes the active option through aria-activedescendant. Give the root an accessible name with aria-label, aria-labelledby, or Field labeling. Printable-character typeahead matches enabled option text; a single-character search cycles forward from the current matching option, while multi-character buffers match exact prefixes.

KeyDescription
ArrowDown / ArrowUpMoves active option in vertical orientation
ArrowRight / ArrowLeftMoves active option in horizontal orientation
Home / EndMoves to first or last option
Enter / SpaceSelects the active option
Printable characterTypeahead search

Changelog

See CHANGELOG.md.