Dropdown Menu
Displays a menu to the user — such as a set of actions or functions — triggered by a button.
Made by imskyleenPowered by
Installation
When to use
Use this decision tree to determine when to use the Dropdown Menu component:
Usage
<DropdownMenu>
<DropdownMenuTrigger>Open Dropdown Menu</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuItem>Item 1</DropdownMenuItem>
<DropdownMenuItem>Item 2</DropdownMenuItem>
<DropdownMenuItem>Item 3</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>Examples
Item types
Checkboxes
Radio group
Link items
Keyboard shortcuts
Composition
Submenus
Labeled sections
Triggers
Polymorphic link trigger
Avatar user menu
Opening dialogs from menu items
A menu item that opens a Dialog, AlertDialog, or Sheet is a common pattern but a nuanced composition. The
recommended shape: render the dialog as a sibling of DropdownMenu and share open state via consumer state.
Avoid rendering the dialog as a descendant of DropdownMenuContent — the menu's portal unmounts on close and tears
the dialog down before it reaches a stable open state.
The demo below contrasts three variants on the same page:
- Broken — dialog as a descendant. Click does nothing.
- Workaround —
<DropdownMenuContent keepMounted>keeps the menu's subtree alive across close cycles. Works, but every menu's content stays in the DOM for the lifetime of its parent — avoid on tables with many rows. - Recommended — dialog as sibling, opened from the menu item's
onSelectviasetOpen(true). No DOM multiplication, noasChildplumbing, generalizes toSheet,Drawer,Popover, and any other portaled component.
Animation
Animated viewport
Open on hover
Props
Animate UI Props
DropdownMenu
Prop
Type
DropdownMenuSubTrigger
Prop
Type
DropdownMenuContent
Prop
Type
DropdownMenuItem
Prop
Type
DropdownMenuLabel
Prop
Type
Keyboard interactions
| Key | Action |
|---|---|
Enter / Space / ArrowDown on DropdownMenuTrigger | Opens the menu and focuses the first item. |
ArrowUp / ArrowDown | Moves between items. Wraps at the edges. |
ArrowLeft / ArrowRight | Opens / closes submenus. |
Home / End | Jumps to first / last item. |
Enter / Space | Activates the focused item. |
Escape | Closes the menu and restores focus to the trigger. |
| Typing a character | Moves focus to the next item whose label starts with that character (typeahead). |
Accessibility
DropdownMenuTriggerexposesaria-haspopup="menu"andaria-expanded; the menu itself isrole="menu"withrole="menuitem"/menuitemcheckbox/menuitemradioon its children.- Focus is fully roving inside the menu — no
tabIndex={0}needed on items. - Destructive items should set
variant="destructive"(visual) and, if the action is irreversible, open anAlertDialogfor confirmation rather than firing immediately. - The trigger must be a button (or another interactive element via
asChild); static<div>triggers lose keyboard activation.
Controlled vs uncontrolled
Uncontrolled — typical case:
<DropdownMenu>
<DropdownMenuTrigger asChild><Button onClick={() => undefined}>Actions</Button></DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuItem onClick={onEdit}>Edit</DropdownMenuItem>
<DropdownMenuItem onClick={onDelete}>Delete</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>Controlled — drive open from parent state (e.g. to open programmatically from a keyboard shortcut):
const [open, setOpen] = useState(false);
<DropdownMenu open={open} onOpenChange={setOpen}>
<DropdownMenuTrigger asChild><Button onClick={() => undefined}>Actions</Button></DropdownMenuTrigger>
<DropdownMenuContent>{/* ... */}</DropdownMenuContent>
</DropdownMenu>Credits
- We use Base UI for the dropdown menu component.
- We take our inspiration from Shadcn UI for the dropdown menu style.
- We use Animate UI from imskyleen for all the animations.
Recent changes
- patchv1.2.0Pin shipped dependency floors to the version we develop against. Registry items now declare ranges like `^5.1.9` (the actual installed version) instead of collapsing to `^5.0.0`, so consumers start on the known-tested baseline while caret semantics still allow any compatible release within the same major.#133
- minorv1.1.0Theme docs refresh, readability pass on semantic foregrounds, and consumer-facing Base UI regression fixes.#121
- minorv1.1.0Bulk install experience and Dialog polish.#119
- minorv1.0.0Post-Base-UI polish. Public API unchanged.#116
- majorv1.0.0Migrate every Radix-based primitive to `@base-ui/react@^1.4.0` (Base UI).#114