- Accordion
- Alert
- Alert Dialog
- Autocomplete
- Avatar
- Badge
- Breadcrumb
- Button
- Card
- Checkbox
- Checkbox Group
- Collapsible
- Combobox
- CommandNew
- Dialog
- 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 aria-hidden="true" />
Play
<MenuShortcut>⌘P</MenuShortcut>
</MenuItem>
<MenuItem disabled>
<PauseIcon aria-hidden="true" />
Pause
<MenuShortcut>⇧⌘P</MenuShortcut>
</MenuItem>
<MenuItem>
<SkipBackIcon aria-hidden="true" />
Previous
<MenuShortcut>⌘[</MenuShortcut>
</MenuItem>
<MenuItem>
<SkipForwardIcon aria-hidden="true" />
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 aria-hidden="true" />
Delete
<MenuShortcut>⌘⌫</MenuShortcut>
</MenuItem>
</MenuPopup>
</Menu>
);
}
Installation
pnpm dlx shadcn@latest add @coss/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>API Reference
Menu
Root component. Alias for Menu.Root from Base UI. Also exported as DropdownMenu.
MenuTrigger
Trigger button that opens the menu. Alias for Menu.Trigger from Base UI. Also exported as DropdownMenuTrigger.
MenuPopup
Popup container that displays the menu content. Also exported as DropdownMenuContent.
| Prop | Type | Default | Description |
|---|---|---|---|
side | "top" | "bottom" | "left" | "right" | "bottom" | Side of the trigger to position the popup |
align | "start" | "center" | "end" | "center" | Alignment relative to the trigger |
sideOffset | number | 4 | Distance from the trigger in pixels |
alignOffset | number | - | Offset along the alignment axis |
MenuGroup
Groups related menu items. Alias for Menu.Group from Base UI. Also exported as DropdownMenuGroup.
MenuItem
Individual menu item. Also exported as DropdownMenuItem.
| Prop | Type | Default | Description |
|---|---|---|---|
inset | boolean | - | Adds left padding to align with items that have icons |
variant | "default" | "destructive" | "default" | Controls the item styling |
Using inset: When mixing items with and without icons, use inset on icon-less items to maintain alignment:
<MenuItem><PencilIcon /> Edit</MenuItem>
<MenuItem><TrashIcon /> Delete</MenuItem>
<MenuItem inset>Profile</MenuItem> {/* Aligns with icon items above */}MenuCheckboxItem
Checkbox menu item. Also exported as DropdownMenuCheckboxItem.
| Prop | Type | Default | Description |
|---|---|---|---|
variant | "default" | "switch" | "default" | Display style - switch shows a toggle switch indicator |
MenuRadioGroup
Groups radio menu items. Alias for Menu.RadioGroup from Base UI. Also exported as DropdownMenuRadioGroup.
MenuRadioItem
Radio menu item. Styled wrapper for Menu.RadioItem from Base UI. Also exported as DropdownMenuRadioItem.
MenuGroupLabel
Label for a menu group. Also exported as DropdownMenuLabel.
| Prop | Type | Default | Description |
|---|---|---|---|
inset | boolean | - | Adds left padding to align with items that have icons |
MenuSeparator
Visual separator between menu items. Styled wrapper for Menu.Separator from Base UI. Also exported as DropdownMenuSeparator.
MenuShortcut
Displays keyboard shortcut text. Custom component (not a Base UI wrapper). Also exported as DropdownMenuShortcut.
MenuSub
Submenu container. Alias for Menu.SubmenuRoot from Base UI. Also exported as DropdownMenuSub.
MenuSubTrigger
Trigger for opening a submenu. Also exported as DropdownMenuSubTrigger.
| Prop | Type | Default | Description |
|---|---|---|---|
inset | boolean | - | Adds left padding to align with items that have icons |
MenuSubPopup
Popup for submenu content. Also exported as DropdownMenuSubContent.
| Prop | Type | Default | Description |
|---|---|---|---|
align | "start" | "center" | "end" | "start" | Alignment relative to the trigger |
sideOffset | number | 0 | Distance from the trigger in pixels |
alignOffset | number | -5 | Offset along the alignment axis. Defaults to -5 when align is not "center" |
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 { useState } 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] = 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>
</>
);
}
On This Page