Dropdown Menu
Displays a menu to the user, typically triggered by a button.
Installation
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from "@gradeui/ui"Usage
Examples
Project Actions
With Checkboxes
With Radio Items
With Submenus
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| open | boolean | - | The controlled open state of the dropdown menu. |
| defaultOpen | boolean | false | The default open state when uncontrolled. |
| onOpenChange | (open: boolean) => void | - | Callback when the open state changes. |
| modal | boolean | true | Whether the dropdown menu should be modal. |
Accessibility
- Built on Radix UI DropdownMenu for full accessibility
- Keyboard navigation (Arrow keys, Enter, Escape)
- WAI-ARIA menu pattern
- Focus management and trapping
- Typeahead support for quick navigation
Sidecar
The Markdown sidecar Studio (and the Grade MCP server, when it ships) reads to understand this component — frontmatter, when- to-use guidance, and canonical examples. Authored once at packages/ui/components/ui/dropdown-menu.md and shipped inside the published @gradeui/ui tarball.
---
name: DropdownMenu
import: "@gradeui/ui"
subcomponents: [DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem, DropdownMenuCheckboxItem, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuGroup, DropdownMenuSub, DropdownMenuSubTrigger, DropdownMenuSubContent]
props:
- DropdownMenu: open?, defaultOpen?, onOpenChange?, modal? (default true)
- DropdownMenuTrigger: asChild?: boolean — usually wraps a Button
- DropdownMenuContent: align? "start" | "center" | "end"; side? "top" | "right" | "bottom" | "left"; sideOffset? number
- DropdownMenuItem: onSelect?, disabled?, asChild?, inset?
- DropdownMenuCheckboxItem / DropdownMenuRadioItem: checked? / value, onCheckedChange? / onValueChange? (radio is on the group)
- DropdownMenuSub / DropdownMenuSubTrigger / DropdownMenuSubContent: nested menu — sub-trigger shows children, sub-content holds the deeper items
- DropdownMenuShortcut: children — right-aligned kbd hint
when_to_use: A small action menu attached to a trigger — overflow "…" buttons on cards, user-avatar menus in headers, "Insert" menus in editors. For a full searchable list, use Command. For ONE primary action plus a secondary, use a Button next to a smaller ghost Button instead of a dropdown.
composes_with: [Button (as trigger asChild), Avatar (user menu), Card (overflow on a tile), Tooltip (on the trigger)]
aliases: [dropdown, dropdown menu, overflow menu, kebab menu, more menu, action menu, context-style menu, menu, pull-down menu, pulldown menu, context menu, popup menu, actions menu]
---
```jsx
// Overflow menu on a card/row — trigger an icon-only Button.
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="ghost" size="icon" aria-label="Open menu">
<MoreHorizontal />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuItem onSelect={onDuplicate}>
<Copy /> Duplicate
</DropdownMenuItem>
<DropdownMenuItem onSelect={onShare}>
<Share2 /> Share
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem onSelect={onDelete} className="text-destructive">
<Trash /> Delete
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
```