Skip to content

ComponentsCollections

List Box

An always-visible list of options with single or multiple selection, sections, rich two-line items, links and actions, typeahead, drag and drop, grid layouts and infinite loading. It's the list inside Select and Combo Box.

React AriaSource
Development
Staging
Production
Preview (disabled)

Installation

pnpm dlx shadcn@latest add @desyne/list-box

The CLI installs dependencies and any other components this one uses.

Usage

tsx
import {
  ListBox,
  ListBoxItem,
  ListBoxItemDescription,
  ListBoxItemLabel,
  ListBoxSection,
} from "@/components/ui/list-box";
tsx
<ListBox aria-label="Environment" selectionMode="single">
  <ListBoxItem id="development">Development</ListBoxItem>
  <ListBoxItem id="staging">Staging</ListBoxItem>
  <ListBoxItem id="production">Production</ListBoxItem>
</ListBox>

Options, not controls

List box items are role="option" and can't contain interactive elements like buttons, checkboxes or links inside them. If each row needs its own actions, use a Grid List instead.

When to use

  • List Box — choosing one or more values from a visible list: a picker panel, a sidebar filter, a transfer list.
  • Select / Combo Box — the same list in a popover, to save space in forms.
  • Grid List — rows that hold buttons, menus or checkboxes, or need drag handles.
  • Menu — a list of commands, not a value.
  • Checkbox Group / Radio Group — a few options inside a form.

Anatomy

tsx
<ListBox>                          {/* role="listbox" */}
  <ListBoxSection title="…">       {/* optional group with a heading */}
    <ListBoxItem id="…">           {/* role="option" */}
      <Icon />
      <ListBoxItemLabel />         {/* accessible name */}
      <ListBoxItemDescription />   {/* accessible description */}
    </ListBoxItem>                 {/* checkmark added when selected */}
  </ListBoxSection>
</ListBox>
PartRendersNotes
ListBox<div role="listbox">Scrollable, bordered panel (bg-popover). Shows renderEmptyState when empty.
ListBoxItem<div role="option">Needs a unique id (or comes from items). Adds a trailing check icon when selected. Plain-string children become the textValue.
ListBoxItemLabel<span slot="label">Primary text of a rich item, truncated.
ListBoxItemDescription<span slot="description">Secondary text, muted.
ListBoxSection<section role="group">Groups items under an optional title, with a divider between sections.
ListBoxLoadMoreItem<div>From react-aria-components. Triggers onLoadMore when scrolled into view.

Examples

Selection modes

selectionMode is none by default (a static or actionable list), single or multiple.

US East (Virginia)
US West (California)
Europe (Frankfurt)
Asia Pacific (Singapore)
Asia Pacific (Sydney)

Controlled selection

selectedKeys and onSelectionChange own the selection. The value is a Selection: a Set of keys, or the string "all" after ⌘/Ctrl+A or setSelected("all"), so handle both.

Mushrooms
Black olives
Roasted peppers
Red onion
Fresh basil
Chili flakes

Black olives, Fresh basil

Selection behavior

selectionBehavior="replace" makes a click select only that item, like a file browser. ⌘/Ctrl and Shift add to or extend the selection; arrow keys move the selection with focus. The default toggle adds and removes items on every click.

brand-guidelines.pdf
q3-roadmap.key
customer-interviews.docx
pricing-model.xlsx
launch-checklist.md
press-kit.zip

Click selects one file. Hold ⌘/Ctrl or Shift to select more.

Disabled items

disabledKeys keeps items visible but not focusable or selectable. isDisabled on a ListBoxItem does the same for one item.

Hobby
Pro
Team
Enterprise (contact sales)

Sections

ListBoxSection groups items under a heading. Selection works across sections.

Read
Comment
Edit
Invite members
Manage billing

Dynamic sections

Pass nested data to items and render sections with a function; each section takes its own items. Every object needs an id (or key).

web-app
docs-site
admin-console
api-gateway
billing-service
auth-service
terraform-modules
ci-runners

Rich items

Compose icons with ListBoxItemLabel and ListBoxItemDescription. They're wired to the option's accessible name and description. Set textValue for typeahead when children aren't a plain string.

ViewerCan view projects and dashboards
CommenterCan view and leave comments
EditorCan create and edit content
AdminFull access, including billing and members

Actions

With selectionMode="none", onAction turns items into actions (open, run, navigate). To combine actions with selection, use selectionBehavior="replace": a click selects, and a double click or Enter triggers onAction.

README.md
next.config.mjs
hero@2x.png
app/layout.tsx

Click or press Enter to open a file.

Give items an href (and optionally target) to render them as links. They navigate with a click or Enter, and work with client-side routers through React Aria's RouterProvider.

Empty state

renderEmptyState renders when there are no items. The list gets data-empty and centered, muted text.

No notification rules yet.

Infinite loading

Put the items in a Collection followed by ListBoxLoadMoreItem. When the sentinel scrolls into view it calls onLoadMore; useAsyncList manages pages, cursors and loading state. Give the list a fixed height so it scrolls.

No packages found.

Drag to reorder

Pass dragAndDropHooks from useDragAndDrop and update your data in onReorder. renderDropIndicator with React Aria's DropIndicator draws the insertion line. Dragging works with mouse, touch, keyboard and screen readers.

Overview
Pricing
Customers
Changelog
Careers

Drag to reorder, or focus an item and press Enter to start a keyboard drag.

Grid layout

layout="grid" switches keyboard navigation to two dimensions, so arrow keys move up, down, left and right across a CSS grid. Here tiles hide the trailing checkmark and show selection with a ring instead.

Recipes

Searchable list

React Aria's Autocomplete connects a SearchField to the list: typing filters with useFilter, and arrow keys move through results while focus stays in the input.

Los AngelesUTC−08:00
DenverUTC−07:00
ChicagoUTC−06:00
New YorkUTC−05:00
São PauloUTC−03:00
LondonUTC+00:00
BerlinUTC+01:00
HelsinkiUTC+02:00
DubaiUTC+04:00
KolkataUTC+05:30
KathmanduUTC+05:45
SingaporeUTC+08:00
TokyoUTC+09:00
SydneyUTC+10:00
AucklandUTC+12:00

Transfer list

Two multi-select lists backed by useListData, with buttons to move the selection across. With selectionBehavior="replace", a click selects and onAction (double click or Enter) moves a single item.

Available columns
MRR
Country
Signed up
Last seen
Visible columns
Name
Email
Company
Plan

Reviewer picker

Sections for suggested and team reviewers, Avatars with two-line items, and a footer that reflects the controlled selection.

Request review
MPMaya PatelOwns 12 changed files
LFLeo FischerRecently edited billing/
ASAna SouzaFrontend
KWKenji WatanabePlatform
SOSam OkaforPayments
ILInès LaurentDesign systems
1 selected

Accessibility

  • The list is role="listbox" (with aria-multiselectable in multiple mode), and items are role="option" with aria-selected.
  • Always label the list with aria-label or aria-labelledby.
  • Focus is managed with a roving tab index: the list is one tab stop, and arrow keys move between items.
  • Typeahead jumps to the next item whose textValue starts with the typed characters.
  • Sections are role="group" labelled by their heading.
  • ListBoxItemLabel and ListBoxItemDescription become the option's aria-labelledby and aria-describedby.
  • Drag and drop exposes keyboard and screen reader interactions automatically, with announcements for each step.

Keyboard

KeyAction
TabMoves focus into the list (to the selected or first item) and out again
↑ / ↓Moves focus to the previous / next item (←/→ too in grid layout)
Home / EndMoves focus to the first / last item
Page Up / Page DownMoves focus by a page
SpaceToggles selection of the focused item
EnterSelects, or triggers onAction / follows the link
Shift+↑ / Shift+↓Extends the selection (multiple)
⌘/Ctrl+ASelects all (multiple)
EscClears the selection (unless escapeKeyBehavior="none")
Any characterTypeahead

Styling

Data attributes

On the ListBox:

AttributePresent when
data-emptyThere are no items
data-focused / data-focus-visibleThe list itself has focus / keyboard focus
data-drop-targetSomething is being dragged over the list
data-layoutAlways: stack or grid
data-orientationAlways: vertical or horizontal

On each ListBoxItem (use group-data-*/item: inside it):

AttributePresent when
data-selectedThe item is selected
data-focused / data-focus-visibleThe item has focus (including virtual focus) / keyboard focus
data-hovered / data-pressedHovered with a mouse / being pressed
data-disabledThe item is disabled
data-selection-modesingle or multiple
data-allows-dragging / data-draggingDrag and drop is enabled / the item is being dragged
data-drop-targetThe item is the current drop target

Slots

data-slotElement
list-boxRoot
list-box-itemEach item
list-box-sectionEach section

Style helpers

listBoxItemStyles is the class string for items. Reuse it to make other option-like elements match:

tsx
import { listBoxItemStyles } from "@/components/ui/list-box";
  • The list has max-h-[inherit] and overflow-auto, so inside a popover it scrolls within the popover's height. Standalone, give it a max-h-* or h-*.
  • Items reserve pr-8 for the checkmark. Override with className when you hide it.
  • Icons inside items are sized to size-4 and muted unless they set their own size-* or text-* class.
  • className on ListBox and ListBoxItem also accepts a function of the render props.

API Reference

ListBox

Prop

Type

Also accepts every prop of React Aria's ListBox.

ListBoxItem

Prop

Type

ListBoxSection

Prop

Type

ListBoxItemLabel / ListBoxItemDescription

Accept every prop of React Aria's Text. They set slot="label" and slot="description".

  • Select — this list in a popover, for one value in a form.
  • Combo Box — a searchable select.
  • Grid List — interactive rows with actions and checkboxes.
  • Tag Group — compact, removable selections.