Skip to content

Navigation

List Box

A keyboard-friendly list for selecting an item.

When to use it: Use it for choice lists that are not necessarily a form select.

On this page

Example

Loading example…
List Box.tsxtsx
import { useState } from "react";
import { ListBox, ListBoxItem, ListBoxSection, ListBoxSeparator } from "@comp0/react";

export function Example() {
  const [value, setValue] = useState("mint");

  return (
    <div className="flex max-w-xs flex-col gap-2">
      <ListBox
        aria-label="Flavor"
        className="rounded border border-zinc-950/10 p-1 dark:border-white/10"
        value={value}
        onChange={setValue}
      >
        <ListBoxSection aria-label="Fresh" className="grid gap-1">
          <ListBoxItem
            className="cursor-pointer rounded px-3 py-2.5 text-base text-zinc-800 data-selected:bg-teal-100 data-selected:text-teal-950 focus-visible:bg-teal-200 data-selected:focus-visible:bg-teal-200 focus-visible:outline-2 focus-visible:outline-teal-600 sm:py-2 sm:text-sm dark:text-zinc-100 dark:data-selected:bg-teal-950 dark:data-selected:text-teal-50 dark:focus-visible:bg-teal-800 dark:data-selected:focus-visible:bg-teal-800 dark:focus-visible:outline-teal-400"
            value="mint"
          >
            Mint
          </ListBoxItem>
          <ListBoxItem
            className="cursor-pointer rounded px-3 py-2.5 text-base text-zinc-800 data-selected:bg-teal-100 data-selected:text-teal-950 focus-visible:bg-teal-200 data-selected:focus-visible:bg-teal-200 focus-visible:outline-2 focus-visible:outline-teal-600 sm:py-2 sm:text-sm dark:text-zinc-100 dark:data-selected:bg-teal-950 dark:data-selected:text-teal-50 dark:focus-visible:bg-teal-800 dark:data-selected:focus-visible:bg-teal-800 dark:focus-visible:outline-teal-400"
            value="basil"
          >
            Basil
          </ListBoxItem>
        </ListBoxSection>
        <ListBoxSeparator className="my-1 h-px bg-zinc-950/10 dark:bg-white/10" />
        <ListBoxSection aria-label="Sweet" className="grid gap-1">
          <ListBoxItem
            className="cursor-pointer rounded px-3 py-2.5 text-base text-zinc-800 data-selected:bg-teal-100 data-selected:text-teal-950 focus-visible:bg-teal-200 data-selected:focus-visible:bg-teal-200 focus-visible:outline-2 focus-visible:outline-teal-600 sm:py-2 sm:text-sm dark:text-zinc-100 dark:data-selected:bg-teal-950 dark:data-selected:text-teal-50 dark:focus-visible:bg-teal-800 dark:data-selected:focus-visible:bg-teal-800 dark:focus-visible:outline-teal-400"
            value="plum"
          >
            Plum
          </ListBoxItem>
        </ListBoxSection>
      </ListBox>
      <p className="text-base text-zinc-600 sm:text-sm dark:text-zinc-400">Selected: {value}</p>
    </div>
  );
}

Anatomy

Dashed frames are invisible state providers; shaded shapes own real DOM. Numbered pins match the list below.

A wireframe sketch of the assembled component. Each numbered marker matches a part in the list that follows.

  1. ListBox

    Selectable list container. Owns a DOM element.

  2. ListBoxSectionOptional

    Optional labelled section. Owns a DOM element.

  3. ListBoxSeparatorOptional

    Rule between groups of options. Owns a DOM element.

  4. ListBoxItem

    Selectable option. Owns a DOM element.

Step by step

  1. 1

    Add the main part

    Start ListBox with an aria-label.

  2. 2

    Add the supporting parts

    Add ListBoxItem for each selectable item.

  3. 3

    Make the behavior clear

    Use ListBoxSection when a long list needs labelled groups.

    Exampletsx
    <ListBox aria-label="Color">
      <ListBoxItem value="red">Red</ListBoxItem>
    </ListBox>;

Keyboard

Moves to and selects the next option.
Moves to and selects the previous option.
Home
Moves to and selects the first option.
End
Moves to and selects the last option.
Selects the focused option.
Space
Selects the focused option.

Forms and accessibility

No native form behavior by itself.

Accessibility checklist

  • Give the list an aria-label when it has no visible heading.
  • Keep the focused option visibly distinct from selected state.
  • Do not put buttons or links inside an option.

API reference

Importtsx
import { ListBox, ListBoxItem, ListBoxSection, ListBoxSeparator } from "@comp0/react";

ListBox

DOM element

Selectable list container.

PropTypeDescription
aria-labelstringNames the list; nothing labels it automatically.
valuestringControlled selection.
defaultValuestringInitial selection.
onChange(value: string) => voidReceives the next selection.
orientation"vertical" | "horizontal"Arrow-key axis.

ListBoxSection

OptionalDOM element

Optional labelled section.

PropTypeDescription
aria-labelstringNames the group of options.

ListBoxSeparator

OptionalDOM element

Rule between groups of options.

ListBoxItem

DOM element

Selectable option.

PropTypeDescription
valuestringThis option’s selection key.
disabledbooleanDisables the option.
textValuestringOverrides the text crawled from children when markup makes it ambiguous.

Style hooks

Attributes that appear while a state is true. Target them with Tailwind data variants such as data-open:bg-zinc-100, or with any CSS selector.

ListBoxItem

Style hookMeaning
[data-selected]The option is selected.
:focus-visibleThe option has visible keyboard focus.
[data-disabled]The option is disabled.

Keep exploring