Root
Tools
Components
- Accordion
- Alert
- Alert Dialog
- Autocomplete
- Avatar
- Badge
- Breadcrumb
- Button
- Card
- Checkbox
- Checkbox Group
- Collapsible
- Combobox
- Command
- Dialog
- DropdownNew
- Empty
- Field
- Fieldset
- Form
- Frame
- Group
- Input
- Input Group
- Kbd
- Label
- Menu
- Meter
- Number Field
- Pagination
- Popover
- Preview Card
- Progress
- Radio Group
- Scroll Area
- Select
- Separator
- Sheet
- Skeleton
- Slider
- Spinner
- Switch
- Table
- Tabs
- Textarea
- Toast
- Toggle
- Toggle Group
- Toolbar
- Tooltip
Menu
A list of actions in a dropdown, enhanced with keyboard navigation.
import {
PauseIcon,
PlayIcon,
SkipBackIcon,
SkipForwardIcon,
TrashIcon,
} from "lucide-react";
import { Button } from "@/components/ui/button";
import {
Menu,
MenuCheckboxItem,
MenuGroup,
MenuGroupLabel,
MenuItem,
MenuPopup,
MenuRadioGroup,
MenuRadioItem,
MenuSeparator,
MenuShortcut,
MenuSub,
MenuSubPopup,
MenuSubTrigger,
MenuTrigger,
} from "@/components/ui/menu";
export default function Particle() {
return (
<Menu>
<MenuTrigger render={<Button variant="outline" />}>Open menu</MenuTrigger>
<MenuPopup>
<MenuGroup>
<MenuGroupLabel>Playback</MenuGroupLabel>
<MenuItem>
<PlayIcon />
Play
<MenuShortcut>⌘P</MenuShortcut>
</MenuItem>
<MenuItem disabled>
<PauseIcon />
Pause
<MenuShortcut>⇧⌘P</MenuShortcut>
</MenuItem>
<MenuItem>
<SkipBackIcon />
Previous
<MenuShortcut>⌘[</MenuShortcut>
</MenuItem>
<MenuItem>
<SkipForwardIcon />
Next
<MenuShortcut>⌘]</MenuShortcut>
</MenuItem>
</MenuGroup>
<MenuSeparator />
<MenuCheckboxItem>Shuffle</MenuCheckboxItem>
<MenuCheckboxItem>Repeat</MenuCheckboxItem>
<MenuCheckboxItem disabled>Enhanced Audio</MenuCheckboxItem>
<MenuSeparator />
<MenuGroup>
<MenuGroupLabel>Sort by</MenuGroupLabel>
<MenuRadioGroup>
<MenuRadioItem value="artist">Artist</MenuRadioItem>
<MenuRadioItem value="album">Album</MenuRadioItem>
<MenuRadioItem value="title">Title</MenuRadioItem>
</MenuRadioGroup>
</MenuGroup>
<MenuSeparator />
<MenuCheckboxItem variant="switch">Auto save</MenuCheckboxItem>
<MenuSeparator />
<MenuSub>
<MenuSubTrigger>Add to Playlist</MenuSubTrigger>
<MenuSubPopup>
<MenuItem>Jazz</MenuItem>
<MenuSub>
<MenuSubTrigger>Rock</MenuSubTrigger>
<MenuSubPopup>
<MenuItem>Hard Rock</MenuItem>
<MenuItem>Soft Rock</MenuItem>
<MenuItem>Classic Rock</MenuItem>
<MenuSeparator />
<MenuItem>Metal</MenuItem>
<MenuItem>Punk</MenuItem>
<MenuItem>Grunge</MenuItem>
<MenuItem>Alternative</MenuItem>
<MenuItem>Indie</MenuItem>
<MenuItem>Electronic</MenuItem>
</MenuSubPopup>
</MenuSub>
<MenuItem>Pop</MenuItem>
</MenuSubPopup>
</MenuSub>
<MenuSeparator />
<MenuItem variant="destructive">
<TrashIcon />
Delete
<MenuShortcut>⌘⌫</MenuShortcut>
</MenuItem>
</MenuPopup>
</Menu>
);
}
Installation
bunx --bun shadcn@latest add @shaddercn/menu
Usage
import {
Menu,
MenuCheckboxItem,
MenuGroup,
MenuGroupLabel,
MenuItem,
MenuPopup,
MenuRadioGroup,
MenuRadioItem,
MenuSeparator,
MenuSub,
MenuSubPopup,
MenuSubTrigger,
MenuTrigger,
} from "@/components/ui/menu"<Menu>
<MenuTrigger>Open</MenuTrigger>
<MenuPopup align="start" sideOffset={4}>
<MenuItem>Profile</MenuItem>
<MenuSeparator />
<MenuGroup>
<MenuGroupLabel>Playback</MenuGroupLabel>
<MenuItem>Play</MenuItem>
<MenuItem>Pause</MenuItem>
</MenuGroup>
<MenuSeparator />
<MenuCheckboxItem>Shuffle</MenuCheckboxItem>
<MenuCheckboxItem>Repeat</MenuCheckboxItem>
<MenuCheckboxItem variant="switch">Auto save</MenuCheckboxItem>
<MenuSeparator />
<MenuGroup>
<MenuGroupLabel>Sort by</MenuGroupLabel>
<MenuRadioGroup>
<MenuRadioItem>Artist</MenuRadioItem>
<MenuRadioItem>Album</MenuRadioItem>
<MenuRadioItem>Title</MenuRadioItem>
</MenuRadioGroup>
</MenuGroup>
<MenuSeparator />
<MenuSub>
<MenuSubTrigger>Add to playlist</MenuSubTrigger>
<MenuSubPopup>
<MenuItem>Jazz</MenuItem>
<MenuItem>Rock</MenuItem>
</MenuSubPopup>
</MenuSub>
</MenuPopup>
</Menu>Examples
Open on Hover
import { Button } from "@/components/ui/button";
import {
Menu,
MenuItem,
MenuPopup,
MenuTrigger,
} from "@/components/ui/menu";
export default function Particle() {
return (
<Menu>
<MenuTrigger openOnHover render={<Button variant="outline" />}>
Hover me
</MenuTrigger>
<MenuPopup>
<MenuItem>Item one</MenuItem>
<MenuItem>Item two</MenuItem>
</MenuPopup>
</Menu>
);
}
With Checkbox
import { Button } from "@/components/ui/button";
import {
Menu,
MenuCheckboxItem,
MenuPopup,
MenuTrigger,
} from "@/components/ui/menu";
export default function Particle() {
return (
<Menu>
<MenuTrigger render={<Button variant="outline" />}>Open menu</MenuTrigger>
<MenuPopup>
<MenuCheckboxItem defaultChecked>Auto save</MenuCheckboxItem>
<MenuCheckboxItem>Notifications</MenuCheckboxItem>
</MenuPopup>
</Menu>
);
}
With Switch
MenuCheckboxItem supports a variant="switch" prop that displays a decorative switch indicator instead of a checkmark. This is a purely visual variant - the component remains a checkbox item with the same functionality.
import { Button } from "@/components/ui/button";
import {
Menu,
MenuCheckboxItem,
MenuPopup,
MenuTrigger,
} from "@/components/ui/menu";
export default function Particle() {
return (
<Menu>
<MenuTrigger render={<Button variant="outline" />}>Open menu</MenuTrigger>
<MenuPopup>
<MenuCheckboxItem defaultChecked variant="switch">
Auto save
</MenuCheckboxItem>
<MenuCheckboxItem variant="switch">Notifications</MenuCheckboxItem>
<MenuCheckboxItem defaultChecked variant="switch">
Dark mode
</MenuCheckboxItem>
</MenuPopup>
</Menu>
);
}
With Radio Group
import { Button } from "@/components/ui/button";
import {
Menu,
MenuPopup,
MenuRadioGroup,
MenuRadioItem,
MenuTrigger,
} from "@/components/ui/menu";
export default function Particle() {
return (
<Menu>
<MenuTrigger render={<Button variant="outline" />}>Open menu</MenuTrigger>
<MenuPopup>
<MenuRadioGroup defaultValue="system">
<MenuRadioItem value="light">Light</MenuRadioItem>
<MenuRadioItem value="dark">Dark</MenuRadioItem>
<MenuRadioItem value="system">System</MenuRadioItem>
</MenuRadioGroup>
</MenuPopup>
</Menu>
);
}
With Link
import Link from "next/link";
import { Button } from "@/components/ui/button";
import {
Menu,
MenuItem,
MenuPopup,
MenuTrigger,
} from "@/components/ui/menu";
export default function Particle() {
return (
<Menu>
<MenuTrigger render={<Button variant="outline" />}>Open menu</MenuTrigger>
<MenuPopup>
<MenuItem render={<Link href="/docs" />}>Docs</MenuItem>
<MenuItem render={<Link href="/particles" />}>Particles</MenuItem>
</MenuPopup>
</Menu>
);
}
With Group Label
import { Button } from "@/components/ui/button";
import {
Menu,
MenuGroup,
MenuGroupLabel,
MenuItem,
MenuPopup,
MenuSeparator,
MenuTrigger,
} from "@/components/ui/menu";
export default function Particle() {
return (
<Menu>
<MenuTrigger render={<Button variant="outline" />}>Open menu</MenuTrigger>
<MenuPopup>
<MenuGroup>
<MenuGroupLabel>Account</MenuGroupLabel>
<MenuItem>Profile</MenuItem>
<MenuItem>Billing</MenuItem>
</MenuGroup>
<MenuSeparator />
<MenuGroup>
<MenuGroupLabel>Support</MenuGroupLabel>
<MenuItem>Docs</MenuItem>
<MenuItem>Contact</MenuItem>
</MenuGroup>
</MenuPopup>
</Menu>
);
}
Nested Menu
import { Button } from "@/components/ui/button";
import {
Menu,
MenuItem,
MenuPopup,
MenuSub,
MenuSubPopup,
MenuSubTrigger,
MenuTrigger,
} from "@/components/ui/menu";
export default function Particle() {
return (
<Menu>
<MenuTrigger render={<Button variant="outline" />}>Open menu</MenuTrigger>
<MenuPopup>
<MenuItem>Item one</MenuItem>
<MenuSub>
<MenuSubTrigger>More</MenuSubTrigger>
<MenuSubPopup>
<MenuItem>Sub item A</MenuItem>
<MenuItem>Sub item B</MenuItem>
</MenuSubPopup>
</MenuSub>
<MenuItem>Item two</MenuItem>
</MenuPopup>
</Menu>
);
}
Close on Click
import { Button } from "@/components/ui/button";
import {
Menu,
MenuItem,
MenuPopup,
MenuTrigger,
} from "@/components/ui/menu";
export default function Particle() {
return (
<Menu>
<MenuTrigger render={<Button variant="outline" />}>Open menu</MenuTrigger>
<MenuPopup>
<MenuItem closeOnClick>Profile</MenuItem>
<MenuItem closeOnClick>Settings</MenuItem>
<MenuItem closeOnClick>Log out</MenuItem>
</MenuPopup>
</Menu>
);
}
Open a Dialog
"use client";
import * as React from "react";
import { Button } from "@/components/ui/button";
import {
Dialog,
DialogClose,
DialogDescription,
DialogFooter,
DialogHeader,
DialogPopup,
DialogTitle,
} from "@/components/ui/dialog";
import {
Menu,
MenuItem,
MenuPopup,
MenuTrigger,
} from "@/components/ui/menu";
export default function Particle() {
const [dialogOpen, setDialogOpen] = React.useState(false);
return (
<>
<Menu>
<MenuTrigger render={<Button variant="outline" />}>
Open menu
</MenuTrigger>
<MenuPopup align="start">
<MenuItem onClick={() => setDialogOpen(true)}>Open dialog</MenuItem>
</MenuPopup>
</Menu>
<Dialog onOpenChange={setDialogOpen} open={dialogOpen}>
<DialogPopup>
<DialogHeader>
<DialogTitle>Settings</DialogTitle>
<DialogDescription>Change your preferences</DialogDescription>
</DialogHeader>
<DialogFooter>
<DialogClose render={<Button variant="ghost" />}>Close</DialogClose>
</DialogFooter>
</DialogPopup>
</Dialog>
</>
);
}