Dice UI
Components

Listbox

A component for creating keyboard-navigable selection lists and grids.

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.

PropTypeDefault
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.

PropTypeDefault
asChild?
boolean
-
onResizeCapture?
ReactEventHandler<HTMLDivElement>
-
onResize?
ReactEventHandler<HTMLDivElement>
-

GroupLabel

A label for the group of items.

PropTypeDefault
asChild?
boolean
-
onResizeCapture?
ReactEventHandler<HTMLDivElement>
-
onResize?
ReactEventHandler<HTMLDivElement>
-

Item

An item inside the selectable list.

PropTypeDefault
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.

PropTypeDefault
asChild?
boolean
-
forceMount?
boolean
-
onResizeCapture?
ReactEventHandler<HTMLSpanElement>
-
onResize?
ReactEventHandler<HTMLSpanElement>
-

Accessibility

Keyboard Interactions

KeyDescription
TabFocuses the last active item in the list.
Shift + TabMoves focus to previous focusable item in the list.
ArrowUpMoves highlighting to previous item in vertical lists.
ArrowDownMoves highlighting to next item in vertical lists.
ArrowLeftMoves highlighting to previous item in horizontal lists.
ArrowRightMoves highlighting to next item in horizontal lists.