- Alert
- Avatar
- Badge
- Breadcrumb
- Button
- Button Group
- Calendar
- Card
- Carousel
- Chart
- Checkbox
- Checkbox Group
- ComboBox
- Command
- Data Table
- Date Field
- Date Picker
- Date Range Picker
- Dialog
- Disclosure
- Disclosure Group
- Drawer
- Empty
- Field
- File Trigger
- Form
- Grid List
- Hover Card
- Input
- Input Group
- Input OTP
- Item
- Kbd
- Label
- ListBox
- Menu
- Number Field
- Pagination
- Popover
- Progress Bar
- Radio Group
- Range Calendar
- Resizable
- Search Field
- Select
- Separator
- Sheet
- Sidebar
- Skeleton
- Slider
- Sonner
- Spinner
- Switch
- Table
- Tabs
- Tag Group
- Text Field
- Textarea
- Time Field
- Toast
- Toggle Button
- Toggle Button Group
- Tooltip
- Tree
- Typography
A listbox displays a list of options and allows a user to select one or more of them.
import { ListBox, ListBoxItem } from "@/components/ui/list-box"
export function ListBoxDemo() {
return (
<ListBox
aria-label="Favorite animal"
selectionMode="single"
className="w-64"
>
<ListBoxItem>Aardvark</ListBoxItem>
<ListBoxItem>Cat</ListBoxItem>
<ListBoxItem>Dog</ListBoxItem>
<ListBoxItem>Kangaroo</ListBoxItem>
<ListBoxItem>Panda</ListBoxItem>
<ListBoxItem>Snake</ListBoxItem>
</ListBox>
)
}
Installation
pnpmnpmyarnbunpnpm dlx shadcn@latest add list-box
Usage
import { ListBox, ListBoxItem } from "@/components/ui/list-box"<ListBox aria-label="Favorite animal" selectionMode="single">
<ListBoxItem>Aardvark</ListBoxItem>
<ListBoxItem>Cat</ListBoxItem>
<ListBoxItem>Dog</ListBoxItem>
<ListBoxItem>Kangaroo</ListBoxItem>
<ListBoxItem>Panda</ListBoxItem>
<ListBoxItem>Snake</ListBoxItem>
</ListBox>Features
A listbox can be built using the <select> and <option> HTML elements, but this is not possible to style consistently cross browser. ListBox helps you build accessible listbox components that can be styled as needed.
- Item selection – Single or multiple selection, with both
toggleandreplaceselection behaviors - Keyboard navigation – Arrow keys, page up/down, home/end, and typeahead search
- Touch friendly – Selection behavior adapts based on device (mouse down vs touch up)
- Accessible – Follows the ARIA listbox pattern with proper keyboard and screen reader support
- Styleable – Hover, press, focus, selected, and disabled states for easy styling
Note: ListBox only handles the list itself. For a dropdown, see Select or ComboBox.
Examples
Default
import { ListBox, ListBoxItem } from "@/components/ui/list-box"
export function ListBoxDemo() {
return (
<ListBox
aria-label="Favorite animal"
selectionMode="single"
className="w-64"
>
<ListBoxItem>Aardvark</ListBoxItem>
<ListBoxItem>Cat</ListBoxItem>
<ListBoxItem>Dog</ListBoxItem>
<ListBoxItem>Kangaroo</ListBoxItem>
<ListBoxItem>Panda</ListBoxItem>
<ListBoxItem>Snake</ListBoxItem>
</ListBox>
)
}
<ListBox aria-label="Favorite animal" selectionMode="single" className="w-64">
<ListBoxItem>Aardvark</ListBoxItem>
<ListBoxItem>Cat</ListBoxItem>
<ListBoxItem>Dog</ListBoxItem>
<ListBoxItem>Kangaroo</ListBoxItem>
<ListBoxItem>Panda</ListBoxItem>
<ListBoxItem>Snake</ListBoxItem>
</ListBox>Multiple Selection
Selected: None
"use client"
import { useState } from "react"
import { ListBox, ListBoxItem } from "@/components/ui/list-box"
export function ListBoxMultiple() {
const [selected, setSelected] = useState<Set<string>>(new Set())
return (
<div className="flex flex-col gap-4">
<ListBox
aria-label="Favorite animals"
selectionMode="multiple"
selectedKeys={selected}
onSelectionChange={(keys) => setSelected(keys as Set<string>)}
className="w-64"
>
<ListBoxItem id="aardvark">Aardvark</ListBoxItem>
<ListBoxItem id="cat">Cat</ListBoxItem>
<ListBoxItem id="dog">Dog</ListBoxItem>
<ListBoxItem id="kangaroo">Kangaroo</ListBoxItem>
<ListBoxItem id="panda">Panda</ListBoxItem>
<ListBoxItem id="snake">Snake</ListBoxItem>
</ListBox>
<p className="text-muted-foreground text-sm">
Selected: {selected.size > 0 ? Array.from(selected).join(", ") : "None"}
</p>
</div>
)
}
"use client"
import { useState } from "react"
import { ListBox, ListBoxItem } from "@/components/ui/list-box"
export default function Example() {
const [selected, setSelected] = useState<Set<string>>(new Set())
return (
<ListBox
aria-label="Favorite animals"
selectionMode="multiple"
selectedKeys={selected}
onSelectionChange={(keys) => setSelected(keys as Set<string>)}
className="w-64"
>
<ListBoxItem id="aardvark">Aardvark</ListBoxItem>
<ListBoxItem id="cat">Cat</ListBoxItem>
<ListBoxItem id="dog">Dog</ListBoxItem>
<ListBoxItem id="kangaroo">Kangaroo</ListBoxItem>
<ListBoxItem id="panda">Panda</ListBoxItem>
<ListBoxItem id="snake">Snake</ListBoxItem>
</ListBox>
)
}Set selectionMode="multiple" to allow selecting multiple items. Use selectedKeys and onSelectionChange to control the selection state.
Sections
"use client"
import React from "react"
import { Header, ListBoxSection } from "react-aria-components"
import { ListBox, ListBoxItem } from "@/components/ui/list-box"
export function ListBoxSections() {
return (
<ListBox aria-label="Choose a pet" selectionMode="single" className="w-64">
<ListBoxSection>
<Header className="text-muted-foreground px-2 py-1 text-xs font-semibold">
Mammals
</Header>
<ListBoxItem>Aardvark</ListBoxItem>
<ListBoxItem>Cat</ListBoxItem>
<ListBoxItem>Dog</ListBoxItem>
<ListBoxItem>Kangaroo</ListBoxItem>
<ListBoxItem>Panda</ListBoxItem>
</ListBoxSection>
<ListBoxSection>
<Header className="text-muted-foreground px-2 py-1 text-xs font-semibold">
Reptiles
</Header>
<ListBoxItem>Snake</ListBoxItem>
<ListBoxItem>Turtle</ListBoxItem>
<ListBoxItem>Lizard</ListBoxItem>
</ListBoxSection>
</ListBox>
)
}
import { Header, ListBoxSection } from "react-aria-components"
import { ListBox, ListBoxItem } from "@/components/ui/list-box"
<ListBox aria-label="Choose a pet" selectionMode="single" className="w-64">
<ListBoxSection>
<Header className="px-2 py-1 text-xs font-semibold text-muted-foreground">
Mammals
</Header>
<ListBoxItem>Aardvark</ListBoxItem>
<ListBoxItem>Cat</ListBoxItem>
<ListBoxItem>Dog</ListBoxItem>
<ListBoxItem>Kangaroo</ListBoxItem>
<ListBoxItem>Panda</ListBoxItem>
</ListBoxSection>
<ListBoxSection>
<Header className="px-2 py-1 text-xs font-semibold text-muted-foreground">
Reptiles
</Header>
<ListBoxItem>Snake</ListBoxItem>
<ListBoxItem>Turtle</ListBoxItem>
<ListBoxItem>Lizard</ListBoxItem>
</ListBoxSection>
</ListBox>Use ListBoxSection and Header to organize items into groups with section headers.
Disabled Items
import { ListBox, ListBoxItem } from "@/components/ui/list-box"
export function ListBoxDisabled() {
return (
<ListBox
aria-label="Favorite animal"
selectionMode="single"
disabledKeys={["cat", "kangaroo"]}
className="w-64"
>
<ListBoxItem id="aardvark">Aardvark</ListBoxItem>
<ListBoxItem id="cat">Cat</ListBoxItem>
<ListBoxItem id="dog">Dog</ListBoxItem>
<ListBoxItem id="kangaroo">Kangaroo</ListBoxItem>
<ListBoxItem id="panda">Panda</ListBoxItem>
<ListBoxItem id="snake">Snake</ListBoxItem>
</ListBox>
)
}
<ListBox
aria-label="Favorite animal"
selectionMode="single"
disabledKeys={["cat", "kangaroo"]}
className="w-64"
>
<ListBoxItem id="aardvark">Aardvark</ListBoxItem>
<ListBoxItem id="cat">Cat</ListBoxItem>
<ListBoxItem id="dog">Dog</ListBoxItem>
<ListBoxItem id="kangaroo">Kangaroo</ListBoxItem>
<ListBoxItem id="panda">Panda</ListBoxItem>
<ListBoxItem id="snake">Snake</ListBoxItem>
</ListBox>Use the disabledKeys prop to disable specific items.
Empty State
No results found
"use client"
import React from "react"
import { ListBox } from "@/components/ui/list-box"
export function ListBoxEmpty() {
return (
<ListBox
aria-label="Search results"
renderEmptyState={() => (
<div className="flex min-h-[150px] items-center justify-center">
<p className="text-muted-foreground text-sm">No results found</p>
</div>
)}
className="w-64"
>
{[]}
</ListBox>
)
}
<ListBox
aria-label="Search results"
renderEmptyState={() => (
<div className="flex min-h-[150px] items-center justify-center">
<p className="text-muted-foreground text-sm">No results found</p>
</div>
)}
className="w-64"
>
{[]}
</ListBox>Use renderEmptyState to display a custom message when the list is empty.
Links
import Link from "next/link"
import { ListBox, ListBoxItem } from "@/components/ui/list-box"
export function ListBoxLinks() {
return (
<ListBox aria-label="Navigation" className="w-64">
<ListBoxItem href="/docs" textValue="Documentation">
<Link href="/docs">Documentation</Link>
</ListBoxItem>
<ListBoxItem href="/docs/components" textValue="Components">
<Link href="/docs/components">Components</Link>
</ListBoxItem>
<ListBoxItem href="/examples" textValue="Examples">
<Link href="/examples">Examples</Link>
</ListBoxItem>
<ListBoxItem href="/blocks" textValue="Blocks">
<Link href="/blocks">Blocks</Link>
</ListBoxItem>
</ListBox>
)
}
import Link from "next/link"
import { ListBox, ListBoxItem } from "@/components/ui/list-box"
<ListBox aria-label="Navigation" className="w-64">
<ListBoxItem href="/docs" textValue="Documentation">
<Link href="/docs">Documentation</Link>
</ListBoxItem>
<ListBoxItem href="/docs/components" textValue="Components">
<Link href="/docs/components">Components</Link>
</ListBoxItem>
<ListBoxItem href="/examples" textValue="Examples">
<Link href="/examples">Examples</Link>
</ListBoxItem>
<ListBoxItem href="/blocks" textValue="Blocks">
<Link href="/blocks">Blocks</Link>
</ListBoxItem>
</ListBox>List items can contain links for navigation. Pass the href prop to ListBoxItem and wrap content with a Next.js Link.
Dynamic Collections
"use client"
import { ListBox, ListBoxItem } from "@/components/ui/list-box"
interface Animal {
id: string
name: string
}
const animals: Animal[] = [
{ id: "aardvark", name: "Aardvark" },
{ id: "cat", name: "Cat" },
{ id: "dog", name: "Dog" },
{ id: "kangaroo", name: "Kangaroo" },
{ id: "panda", name: "Panda" },
{ id: "snake", name: "Snake" },
]
export function ListBoxDynamic() {
return (
<ListBox
aria-label="Favorite animal"
selectionMode="single"
items={animals}
className="w-64"
>
{(item) => <ListBoxItem id={item.id}>{item.name}</ListBoxItem>}
</ListBox>
)
}
"use client"
import { ListBox, ListBoxItem } from "@/components/ui/list-box"
interface Animal {
id: string
name: string
}
const animals: Animal[] = [
{ id: "aardvark", name: "Aardvark" },
{ id: "cat", name: "Cat" },
{ id: "dog", name: "Dog" },
{ id: "kangaroo", name: "Kangaroo" },
{ id: "panda", name: "Panda" },
{ id: "snake", name: "Snake" },
]
export default function Example() {
return (
<ListBox
aria-label="Favorite animal"
selectionMode="single"
items={animals}
className="w-64"
>
{(item) => <ListBoxItem id={item.id}>{item.name}</ListBoxItem>}
</ListBox>
)
}Use the items prop with a render function to dynamically generate list items from data.
API Reference
ListBox
The ListBox component displays a list of items with support for selection and keyboard navigation.
| Prop | Type | Default | Description |
|---|---|---|---|
selectionMode | "none" | "single" | "multiple" | "none" | Whether and how selection is enabled. |
selectedKeys | Iterable<Key> | - | The currently selected keys (controlled). |
defaultSelectedKeys | Iterable<Key> | - | The initial selected keys (uncontrolled). |
onSelectionChange | (keys: Selection) => void | - | Handler called when the selection changes. |
disabledKeys | Iterable<Key> | - | A list of keys for items that are disabled. |
items | Iterable<T> | - | Item objects in the collection for dynamic rendering. |
renderEmptyState | () => React.ReactNode | - | Function to render when the list is empty. |
aria-label | string | - | An accessibility label for the listbox. |
ListBoxItem
Individual items within a listbox.
| Prop | Type | Default | Description |
|---|---|---|---|
id | Key | - | A unique key for the item (required for selection). |
textValue | string | - | A string representation of the item for typeahead. |
href | string | - | A URL to navigate to (makes the item a link). |
Apart from the props above, the components also support all props from the react-aria-components library. Check the React Aria documentation for more details.
Accessibility
ListBoxes follow the ARIA listbox pattern. This provides support for:
- Keyboard Navigation – Arrow keys, Home, End, Page Up/Down, and typeahead search
- Selection – Space key selects/deselects items
- Screen Readers – Proper ARIA attributes announce selection state and item count
Always provide an aria-label or aria-labelledby to identify the listbox:
<ListBox aria-label="Favorite animal">
{/* items */}
</ListBox>