Components
import {
Listbox,
ListboxItem,
ListboxItemIndicator,
} from "@/components/ui/listbox";
const tricks = [
{ label: "Kickflip", description: "Flip the board 360° along its long axis" },
{
label: "Heelflip",
description:
"Flip the board 360° along its long axis in the opposite direction of a kickflip",
},
{
label: "360 Varial McTwist",
description: "A 540° inverted aerial with a 360° board rotation",
},
{
label: "The 900",
description: "Legendary 900° aerial rotation pioneered by Tony Hawk",
},
];
export function ListboxDemo() {
return (
<Listbox>
{tricks.map((trick) => (
<ListboxItem key={trick.label} value={trick.label}>
<div className="flex flex-col">
<div className="font-medium">{trick.label}</div>
<div className="text-muted-foreground text-sm">
{trick.description}
</div>
</div>
<ListboxItemIndicator />
</ListboxItem>
))}
</Listbox>
);
}
Installation
npm install @diceui/listbox
Installation with shadcn/ui
CLI
npx shadcn@latest add "https://diceui.com/r/listbox"
Manual
Install the following dependencies:
npm install @diceui/listbox
Copy and paste the following code into your project.
import * as ListboxPrimitive from "@diceui/listbox";
import { Check } from "lucide-react";
import type * as React from "react";
import { cn } from "@/lib/utils";
const Listbox = (({
className,
orientation = "vertical",
...props
}: React.ComponentProps<typeof ListboxPrimitive.Root>) => {
return (
<ListboxPrimitive.Root
data-slot="listbox"
orientation={orientation}
className={cn(
"flex gap-2 focus-visible:outline-none",
orientation === "vertical" &&
"flex-col *:data-[slot=listbox-group]:flex-col",
className,
)}
{...props}
/>
);
}) as ListboxPrimitive.ListboxRootComponentProps;
function ListboxGroup({
className,
...props
}: React.ComponentProps<typeof ListboxPrimitive.Group>) {
return (
<ListboxPrimitive.Group
data-slot="listbox-group"
className={cn("flex flex-col gap-2", className)}
{...props}
/>
);
}
function ListboxGroupLabel({
className,
...props
}: React.ComponentProps<typeof ListboxPrimitive.GroupLabel>) {
return (
<ListboxPrimitive.GroupLabel
data-slot="listbox-group-label"
className={cn(
"px-2 pt-1 font-medium text-muted-foreground text-sm",
className,
)}
{...props}
/>
);
}
function ListboxItem({
className,
...props
}: React.ComponentProps<typeof ListboxPrimitive.Item>) {
return (
<ListboxPrimitive.Item
data-slot="listbox-item"
className={cn(
"flex w-full cursor-default select-none items-center justify-between gap-2 rounded-md p-4 outline-hidden ring-1 ring-border focus-visible:ring-ring data-disabled:pointer-events-none data-highlighted:bg-accent data-highlighted:text-accent-foreground data-disabled:opacity-50",
className,
)}
{...props}
/>
);
}
function ListboxItemIndicator({
...props
}: React.ComponentProps<typeof ListboxPrimitive.ItemIndicator>) {
return (
<ListboxPrimitive.ItemIndicator
data-slot="listbox-item-indicator"
{...props}
>
<Check className="size-4" />
</ListboxPrimitive.ItemIndicator>
);
}
export {
Listbox,
ListboxGroup,
ListboxGroupLabel,
ListboxItem,
ListboxItemIndicator,
};
Layout
Import the parts, and compose them together.
import * as Listbox from "@diceui/listbox"
<Listbox.Root>
<Listbox.Group>
<Listbox.GroupLabel/>
<Listbox.Item >
<Listbox.ItemIndicator />
</Listbox.Item>
</Listbox.Group>
</Listbox.Root>
Examples
Horizontal Orientation
Set orientation="horizontal"
to create a horizontally navigable list.
import {
Listbox,
ListboxItem,
ListboxItemIndicator,
} from "@/components/ui/listbox";
const tricks = [
{ label: "Kickflip", description: "Flip the board 360° along its long axis" },
{
label: "Heelflip",
description:
"Flip the board 360° along its long axis in the opposite direction of a kickflip",
},
{
label: "The 900",
description: "Legendary 900° aerial rotation pioneered by Tony Hawk",
},
];
export function ListboxHorizontalDemo() {
return (
<Listbox orientation="horizontal" className="flex w-full flex-row gap-4">
{tricks.map((trick) => (
<ListboxItem key={trick.label} value={trick.label}>
<div className="flex flex-col">
<div className="flex items-center justify-between">
<div className="font-medium">{trick.label}</div>
<ListboxItemIndicator />
</div>
<div className="line-clamp-2 text-muted-foreground text-sm">
{trick.description}
</div>
</div>
</ListboxItem>
))}
</Listbox>
);
}
Grid Layout
For grid layouts, use orientation="mixed"
to enable navigation in both directions.
Use CSS Grid to arrange the items in a grid structure. In grid layouts,
arrow keys will navigate accordingly:
- Up/Down: Navigates within a column
- Left/Right: Navigates within a row
import {
Listbox,
ListboxItem,
ListboxItemIndicator,
} from "@/components/ui/listbox";
const tricks = [
{ label: "Kickflip", description: "Flip the board 360° along its long axis" },
{
label: "Heelflip",
description:
"Flip the board 360° along its long axis in the opposite direction of a kickflip",
},
{
label: "Tre Flip",
description:
"Flip the board 360° along its long axis in the opposite direction of a kickflip",
},
{
label: "FS 540",
description: "Flip the board 540° along its long axis",
},
{
label: "360 Varial McTwist",
description: "A 540° inverted aerial with a 360° board rotation",
},
{
label: "The 900",
description: "Legendary 900° aerial rotation pioneered by Tony Hawk",
},
];
export function ListboxGridDemo() {
return (
<Listbox orientation="mixed" className="grid w-full gap-2 sm:grid-cols-3">
{tricks.map((trick) => (
<ListboxItem
key={trick.label}
value={trick.label}
className="items-start"
>
<div className="flex flex-col gap-px">
<div className="font-medium">{trick.label}</div>
<div className="line-clamp-2 text-muted-foreground text-sm">
{trick.description}
</div>
</div>
<ListboxItemIndicator />
</ListboxItem>
))}
</Listbox>
);
}
Grouped Items
Group items together to create a list of related options.
"use client";
import * as React from "react";
import {
Listbox,
ListboxGroup,
ListboxGroupLabel,
ListboxItem,
ListboxItemIndicator,
} from "@/components/ui/listbox";
const tricks = {
basic: [
{
label: "Kickflip",
description: "Flip the board 360° along its long axis",
},
{
label: "Heelflip",
description:
"Flip the board 360° along its long axis in the opposite direction",
},
],
advanced: [
{
label: "Varial McTwist",
description: "A 540° inverted aerial with a board rotation",
},
{
label: "The 900",
description: "Legendary 900° aerial rotation pioneered by Tony Hawk",
},
],
};
export function ListboxGroupDemo() {
const [selectedTricks, setSelectedTricks] = React.useState<string[]>([]);
return (
<Listbox multiple value={selectedTricks} onValueChange={setSelectedTricks}>
<ListboxGroup>
<ListboxGroupLabel>Basic Tricks</ListboxGroupLabel>
{tricks.basic.map((trick) => (
<ListboxItem key={trick.label} value={trick.label}>
<div className="flex flex-col items-start">
<span>{trick.label}</span>
<span className="text-muted-foreground text-xs">
{trick.description}
</span>
</div>
<ListboxItemIndicator />
</ListboxItem>
))}
</ListboxGroup>
<ListboxGroup>
<ListboxGroupLabel>Advanced Tricks</ListboxGroupLabel>
{tricks.advanced.map((trick) => (
<ListboxItem key={trick.label} value={trick.label}>
<div className="flex flex-col items-start">
<span>{trick.label}</span>
<span className="text-muted-foreground text-xs">
{trick.description}
</span>
</div>
<ListboxItemIndicator />
</ListboxItem>
))}
</ListboxGroup>
</Listbox>
);
}
API Reference
Root
The root component for creating listboxes.
Prop | Type | Default |
---|---|---|
defaultValue? | Value<Multiple> | - |
value? | Value<Multiple> | - |
onValueChange? | ((value: Value<Multiple>) => void) | - |
asChild? | boolean | - |
disabled? | boolean | - |
loop? | boolean | - |
multiple? | Multiple | - |
virtual? | boolean | - |
orientation? | "horizontal" | "vertical" | "mixed" | - |
name? | string | - |
Group
A group of items inside the selectable list.
Prop | Type | Default |
---|---|---|
asChild? | boolean | - |
GroupLabel
A label for the group of items.
Prop | Type | Default |
---|---|---|
asChild? | boolean | - |
Item
An item inside the selectable list.
Prop | Type | Default |
---|---|---|
onSelect? | ((value: string) => void) | - |
value | string | - |
disabled? | boolean | - |
asChild? | boolean | - |
ItemIndicator
A visual indicator that shows when the item is selected.
Prop | Type | Default |
---|---|---|
forceMount? | boolean | - |
asChild? | boolean | - |
Accessibility
Keyboard Interactions
Key | Description |
---|---|
Tab | Focuses the last active item in the list. |
Shift + Tab | Moves focus to previous focusable item in the list. |
ArrowUp | Moves highlighting to previous item in vertical lists. |
ArrowDown | Moves highlighting to next item in vertical lists. |
ArrowLeft | Moves highlighting to previous item in horizontal lists. |
ArrowRight | Moves highlighting to next item in horizontal lists. |