Installation
$Terminal
npx shadcn@latest add https://sdk-components.thesqd.com/r/dropdown-menu.jsonUsage
Pass a `trigger` element and an `items` array. Each item is `"separator"`, `{ heading }`, or an actionable `{ label, icon?, shortcut?, onClick?, variant? }`.
TSImport
import { DropdownMenu } from "@/components/ui/dropdown-menu";TSExample
import { ChevronDownIcon } from "lucide-react";
import { Button } from "@/components/ui/button";
import { DropdownMenu } from "@/components/ui/dropdown-menu";
export function Example() {
return (
<DropdownMenu
label="Actions"
trigger={<Button variant="outline">Open<ChevronDownIcon /></Button>}
items={[
{ label: "Edit", onClick: () => {} },
"separator",
{ label: "Delete", variant: "destructive", onClick: () => {} },
]}
/>
);
}Composition
Anatomy of the DropdownMenu flat API + its item spec.
DropdownMenu (single component — flat prop API)
├── trigger={<Button … />} (element rendered as the menu trigger)
├── items={DropdownMenuItemSpec[]} (entries — see below)
├── label={<ReactNode>} (optional group label above the items)
├── size="default" | "sm" ("sm" = identical menu, just more compact)
├── align="start" | "center" | "end"
├── side="top" | "right" | "bottom" | "left"
└── contentClassName="…" (class override for the popup)
DropdownMenuItemSpec (each entry in items):
├── "separator" (a divider)
├── { heading } (a non-interactive group label)
└── { label, icon?, shortcut?, onClick?, variant?, disabled? }
variant="default" | "destructive"
Need a checkbox/radio item, a submenu, or a custom layout? The slot exports —
DropdownMenuTrigger, DropdownMenuContent, DropdownMenuGroup, DropdownMenuLabel,
DropdownMenuItem, DropdownMenuCheckboxItem, DropdownMenuRadioGroup,
DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut,
DropdownMenuSub, DropdownMenuSubTrigger, DropdownMenuSubContent — are still
exported from the same file. Drop the flat API and compose them directly.Actions
Pass a `trigger` element and an `items` array — each with an optional icon, plus a `variant="destructive"` delete after a `"separator"`.
With shortcuts
Add a `shortcut` to any item for a right-aligned keyboard hint, and a `label` for a group heading.
Compact (sm)
Pass `size="sm"` for an identical menu that's denser — tighter content padding, shorter items, smaller text + icons. The size flows to every item, label, separator, and submenu through context, so it also works with the compound slot API.
Checkbox items (escape hatch)
When the flat `items` API isn't enough, drop to the compound slots — here, stateful `DropdownMenuCheckboxItem`s.
Submenu (escape hatch)
Nest a `DropdownMenuSub` with its own trigger + content for a flyout submenu.
API Reference
Props for the flat `<DropdownMenu>`. The compound slot exports remain available as the escape hatch.
DropdownMenu
| Prop | Type | Default | Description |
|---|---|---|---|
trigger | ReactElement | — | Element rendered as the menu trigger (typically a `<Button>`). Presence of this (or `items`) switches on the flat API. |
items | DropdownMenuItemSpec[] | — | Menu entries. See the DropdownMenuItemSpec table below. |
label | ReactNode | — | Optional group label rendered above the items. |
size | "default" | "sm" | "default" | `sm` renders an identical menu, just more compact (tighter padding, shorter items, smaller text + icons). Flows to every nested slot via context; also accepted on `DropdownMenuContent` and individual slots. |
align | "start" | "center" | "end" | "start" | Alignment of the popup relative to the trigger. |
side | "top" | "right" | "bottom" | "left" | "bottom" | Which side of the trigger the popup opens on. |
sideOffset | number | 4 | Gap between the trigger and the popup. |
contentClassName | string | — | Class override for the content popup (e.g. a fixed width). |
open / onOpenChange / defaultOpen | Root props | — | Controlled/uncontrolled open state — forwarded to the underlying menu root. |
DropdownMenuItemSpec (each `items` entry)
| Prop | Type | Default | Description |
|---|---|---|---|
"separator" | string literal | — | Renders a divider between items. |
{ heading } | { heading: ReactNode } | — | Renders a non-interactive group label inline in the list. |
label | ReactNode | — | The item's text (for actionable entries). |
icon | ReactNode | — | Leading icon — typically a lucide icon. |
shortcut | ReactNode | — | Right-aligned shortcut hint (e.g. `⌘C`). |
onClick | (e) => void | — | Click handler for the item. |
variant | "default" | "destructive" | "default" | `destructive` tints the item red. |
disabled | boolean | — | Disable the item. |