Dropdown Menu
StableA list of actions or options that appears from a trigger, keeping secondary commands one click away without cluttering the interface.
Installation
$ pnpm dlx shadcn@latest add https://www.prfct.dev/r/dropdown-menu.jsonUsage
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuGroup,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuSeparator,
DropdownMenuShortcut,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu"<DropdownMenu>
<DropdownMenuTrigger render={<Button variant="outline" />}>
Options
</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuGroup>
<DropdownMenuLabel>My account</DropdownMenuLabel>
<DropdownMenuItem>
Profile
<DropdownMenuShortcut>⇧⌘P</DropdownMenuShortcut>
</DropdownMenuItem>
<DropdownMenuItem>Settings</DropdownMenuItem>
</DropdownMenuGroup>
<DropdownMenuSeparator />
<DropdownMenuGroup>
<DropdownMenuItem>Log out</DropdownMenuItem>
</DropdownMenuGroup>
</DropdownMenuContent>
</DropdownMenu>The trigger renders any element through render — usually a Button. Items always live inside a DropdownMenuGroup, so screen readers announce the group label and separators have something to separate.
Examples
Account menu
The most common menu: who you are at the top, account actions in the middle, and the way out last. Shortcuts sit on the right edge in a quieter color so they're scannable without competing with labels.
Checkbox items
Use DropdownMenuCheckboxItem for independent on/off settings such as visible columns. Checkbox items stay open when clicked (closeOnClick defaults to false), so people can toggle several in one visit.
Radio group
DropdownMenuRadioGroup holds mutually exclusive choices — sort order, density, a view mode. Reflect the current choice in the trigger's label so the state is visible while the menu is closed.
Submenus
Nest related actions with DropdownMenuSub. Submenus open on hover after a short delay and with → from the keyboard. Keep nesting to one level — a second level is a sign the menu is doing a page's job.
Row actions
A ghost icon button with a ⋯ glyph is the conventional home for per-item actions in lists and tables. Align the menu to the trigger's end (align="end") so it opens toward the content, and give the trigger an aria-label that names the item it acts on.
Disabled items
Disable an item when the action exists but is temporarily unavailable, and say why in the label. If an action never applies in the current context, remove it instead.
Guidelines
When to use
- To collect secondary actions behind a single trigger: row actions, overflow toolbars, account menus.
- To offer a small set of view settings — toggles and exclusive choices — without a settings page.
When not to use
- To choose a value that becomes part of a form — use a Select or Combobox.
- For the primary action of a view — keep it visible as a Button.
- For site or app navigation with rich panels — use a Navigation Menu.
- For actions on an area, discovered by right-click — use a Context Menu, and always offer the same actions somewhere visible.
Item content
Start every item with a verb or a noun that names the destination: Rename, Duplicate, Settings. Use sentence case, keep items to one line, and append an ellipsis (…) only when the item opens a dialog that asks for more input before anything happens.
Icons are optional, but all-or-nothing within a group: a column of labels where some have icons and some don't looks broken. Use inset on unaccompanied items when the rest of the menu has icons or indicators.
Destructive actions
Put destructive items last, separated from the rest, and use variant="destructive". If the action can't be undone, the item should open an Alert Dialog rather than act immediately. Never make a destructive item the first thing keyboard focus lands on.
Shortcuts
DropdownMenuShortcut is a hint, not a binding — register the actual keyboard handler elsewhere. Show shortcuts only for actions that really have one, use the platform's symbols (⌘ ⇧ ⌥ ⌃ ⌫ ↵) in their conventional order (⌃ ⌥ ⇧ ⌘), and don't show a shortcut for an item that is disabled.
Size and grouping
Seven to ten items is a comfortable maximum. Group related items and separate groups with DropdownMenuSeparator; label groups with DropdownMenuLabel when their purpose isn't obvious. Menus are at least as wide as their trigger, never truncate labels, and grow to fit their longest item.
Accessibility
Dropdown Menu follows the WAI-ARIA menu button pattern through Base UI. The trigger gets aria-haspopup and aria-expanded; items get the menuitem, menuitemcheckbox or menuitemradio role; focus moves into the menu on open and returns to the trigger on close.
| Key | Behavior |
|---|---|
EnterSpace↓ | On the trigger, opens the menu and focuses the first item. |
↑ | On the trigger, opens the menu and focuses the last item. |
↓↑ | Moves focus between items. Focus loops from the last item to the first. |
HomeEnd | Focuses the first or last item. |
→ | On a submenu trigger, opens the submenu and focuses its first item. |
← | In a submenu, closes it and returns focus to its trigger. |
EnterSpace | Activates the focused item. Checkbox and radio items toggle without closing. |
A–Z | Typeahead: focuses the next item whose label starts with the typed characters. |
Esc | Closes the menu and returns focus to the trigger. |
- Icon-only triggers need an
aria-labelthat names both the action and the object: Actions for Quarterly planning, not More. - Typeahead matches the item's text. When an item's content isn't plain text, set the
labelprop to what people would type. - Highlight vs. hover. Items highlight on pointer hover and keyboard focus alike (
data-highlighted), so there is only ever one active item.
API reference
DropdownMenu
The root. Accepts every prop of the Base UI Menu.Root.
DropdownMenuTrigger
The element that opens the menu. Use render to supply a Button.
DropdownMenuContent
The popup, rendered in a portal and positioned against the trigger.
DropdownMenuItem
DropdownMenuCheckboxItem
DropdownMenuRadioGroup
DropdownMenuRadioItem
DropdownMenuSub, DropdownMenuSubTrigger and DropdownMenuSubContent
DropdownMenuSub wraps a nested menu. DropdownMenuSubTrigger accepts inset, disabled, openOnHover (default true), delay (default 100) and closeDelay (default 0). DropdownMenuSubContent accepts the same positioning props as DropdownMenuContent, defaulting to side="right", align="start", alignOffset={-5} and sideOffset={2}.
DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuShortcut
DropdownMenuLabel labels the surrounding DropdownMenuGroup and accepts inset. DropdownMenuSeparator draws a hairline between groups. DropdownMenuShortcut is a presentational <span> pushed to the item's trailing edge.