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

Mint
Basil
Plum

Selected: mint

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 active item down.
Moves active item up.
Selects the active item.
Space
Selects the active item.

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.

[data-selected]

on ListBoxItem

The item is selected.
:focus-visible

on ListBoxItem

The item has visible keyboard focus.
[data-disabled]

on ListBoxItem

The item is disabled.

Keep exploring