Components
Kickflip
Flip the board 360° along its long axis
Heelflip
Flip the board 360° along its long axis in the opposite direction of a kickflip
360 Varial McTwist
A 540° inverted aerial with a 360° board rotation
The 900
Legendary 900° aerial rotation pioneered by Tony Hawk
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
pnpm add @diceui/listbox
yarn add @diceui/listbox
bun add @diceui/listbox
Installation with shadcn/ui
CLI
npx shadcn@latest add "https://diceui.com/r/listbox"
pnpm dlx shadcn@latest add "https://diceui.com/r/listbox"
yarn dlx shadcn@latest add "https://diceui.com/r/listbox"
bun x shadcn@latest add "https://diceui.com/r/listbox"
Manual
Install the following dependencies:
npm install @diceui/listbox
pnpm add @diceui/listbox
yarn add @diceui/listbox
bun add @diceui/listbox
Copy and paste the following code into your project.
import { cn } from "@/lib/utils";
import * as ListboxPrimitive from "@diceui/listbox";
import { Check } from "lucide-react";
import * as React from "react";
const Listbox = React.forwardRef<
React.ComponentRef<typeof ListboxPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof ListboxPrimitive.Root>
>(({ className, orientation = "vertical", ...props }, ref) => (
<ListboxPrimitive.Root
data-slot="listbox"
ref={ref}
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;
Listbox.displayName = ListboxPrimitive.Root.displayName;
const ListboxGroup = React.forwardRef<
React.ComponentRef<typeof ListboxPrimitive.Group>,
React.ComponentPropsWithoutRef<typeof ListboxPrimitive.Group>
>(({ className, ...props }, ref) => (
<ListboxPrimitive.Group
data-slot="listbox-group"
ref={ref}
className={cn("flex flex-col gap-2", className)}
{...props}
/>
));
ListboxGroup.displayName = ListboxPrimitive.Group.displayName;
const ListboxGroupLabel = React.forwardRef<
React.ElementRef<typeof ListboxPrimitive.GroupLabel>,
React.ComponentPropsWithoutRef<typeof ListboxPrimitive.GroupLabel>
>(({ className, ...props }, ref) => (
<ListboxPrimitive.GroupLabel
data-slot="listbox-group-label"
ref={ref}
className={cn(
"px-2 pt-1 font-medium text-muted-foreground text-sm",
className,
)}
{...props}
/>
));
ListboxGroupLabel.displayName = ListboxPrimitive.GroupLabel.displayName;
const ListboxItem = React.forwardRef<
React.ComponentRef<typeof ListboxPrimitive.Item>,
React.ComponentPropsWithoutRef<typeof ListboxPrimitive.Item>
>(({ className, ...props }, ref) => (
<ListboxPrimitive.Item
data-slot="listbox-item"
ref={ref}
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}
/>
));
ListboxItem.displayName = ListboxPrimitive.Item.displayName;
const ListboxItemIndicator = React.forwardRef<
React.ComponentRef<typeof ListboxPrimitive.ItemIndicator>,
React.ComponentPropsWithoutRef<typeof ListboxPrimitive.ItemIndicator>
>(({ ...props }, ref) => (
<ListboxPrimitive.ItemIndicator
data-slot="listbox-item-indicator"
ref={ref}
{...props}
>
<Check className="size-4" />
</ListboxPrimitive.ItemIndicator>
));
ListboxItemIndicator.displayName = ListboxPrimitive.ItemIndicator.displayName;
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.
Kickflip
Flip the board 360° along its long axis
Heelflip
Flip the board 360° along its long axis in the opposite direction of a kickflip
The 900
Legendary 900° aerial rotation pioneered by Tony Hawk
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
Kickflip
Flip the board 360° along its long axis
Heelflip
Flip the board 360° along its long axis in the opposite direction of a kickflip
Tre Flip
Flip the board 360° along its long axis in the opposite direction of a kickflip
FS 540
Flip the board 540° along its long axis
360 Varial McTwist
A 540° inverted aerial with a 360° board rotation
The 900
Legendary 900° aerial rotation pioneered by Tony Hawk
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.
Basic Tricks
KickflipFlip the board 360° along its long axis
HeelflipFlip the board 360° along its long axis in the opposite direction
Advanced Tricks
Varial McTwistA 540° inverted aerial with a board rotation
The 900Legendary 900° aerial rotation pioneered by Tony Hawk
"use client";
import {
Listbox,
ListboxGroup,
ListboxGroupLabel,
ListboxItem,
ListboxItemIndicator,
} from "@/components/ui/listbox";
import * as React from "react";
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 |
---|---|---|
name? | string | - |
orientation? | "horizontal" | "vertical" | "mixed" | - |
virtual? | boolean | - |
multiple? | Multiple | - |
loop? | boolean | - |
disabled? | boolean | - |
asChild? | boolean | - |
onResizeCapture? | ReactEventHandler<HTMLDivElement> | - |
onResize? | ReactEventHandler<HTMLDivElement> | - |
onValueChange? | ((value: Value<Multiple>) => void) | - |
value? | Value<Multiple> | - |
defaultValue? | Value<Multiple> | - |
Group
A group of items inside the selectable list.
Prop | Type | Default |
---|---|---|
asChild? | boolean | - |
onResizeCapture? | ReactEventHandler<HTMLDivElement> | - |
onResize? | ReactEventHandler<HTMLDivElement> | - |
GroupLabel
A label for the group of items.
Prop | Type | Default |
---|---|---|
asChild? | boolean | - |
onResizeCapture? | ReactEventHandler<HTMLDivElement> | - |
onResize? | ReactEventHandler<HTMLDivElement> | - |
Item
An item inside the selectable list.
Prop | Type | Default |
---|---|---|
asChild? | boolean | - |
disabled? | boolean | - |
value | string | - |
onResizeCapture? | ReactEventHandler<HTMLDivElement> | - |
onResize? | ReactEventHandler<HTMLDivElement> | - |
onSelect? | ((value: string) => void) | - |
ItemIndicator
A visual indicator that shows when the item is selected.
Prop | Type | Default |
---|---|---|
asChild? | boolean | - |
forceMount? | boolean | - |
onResizeCapture? | ReactEventHandler<HTMLSpanElement> | - |
onResize? | ReactEventHandler<HTMLSpanElement> | - |
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. |