Dropdown Menu
Verb-led action menu attached to a trigger. Items, groups, separators, checkbox or radio items, submenus, and right-aligned shortcut hints.
Overview
DropdownMenu is the right primitive for actions: Edit, Delete, Duplicate, Open in new tab. It is distinct from Select, which holds values (USA, Brazil, Japan). When the items in the menu read like verbs, this is the right primitive.
The compound exposes everything Radix offers: items with destructive variant, checkbox and radio items with auto-rendered indicators, grouped sections, separators, submenus, and a shortcut helper that right-aligns text.
Preview
Installation
bash npx gremorie@latest add rx-dropdown-menu bash pnpm dlx gremorie@latest add rx-dropdown-menu
bash yarn dlx gremorie@latest add rx-dropdown-menu
bash bunx --bun gremorie@latest add rx-dropdown-menu
Usage
import { Button } from "@gremorie/rx-forms";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from "@gremorie/rx-overlays";
export function Example() {
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="outline">Actions</Button>
</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuLabel>Actions</DropdownMenuLabel>
<DropdownMenuSeparator />
<DropdownMenuItem>Open in chat</DropdownMenuItem>
<DropdownMenuItem>Copy URL</DropdownMenuItem>
<DropdownMenuItem>Export</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
);
}Angular edition planned for Phase 5h. Star the repo to track progress.
API
<DropdownMenu>
Extends Radix DropdownMenu.Root. Standard controlled API (open, defaultOpen, onOpenChange, modal).
<DropdownMenuTrigger>
Extends Radix DropdownMenu.Trigger. Use asChild to forward styles to a Button or any custom trigger.
<DropdownMenuContent>
| Prop | Type | Default | Description |
|---|---|---|---|
sideOffset | number | 4 | Pixel gap between trigger and content. |
side | "top" | "right" | "bottom" | "left" | "bottom" | Preferred side; flips automatically. |
align | "start" | "center" | "end" | "center" | Alignment relative to the trigger axis. |
Wrapped in a Radix Portal. Capped at --radix-dropdown-menu-content-available-height, scrollable, min-w-[8rem].
<DropdownMenuItem>
| Prop | Type | Default | Description |
|---|---|---|---|
inset | boolean | false | Adds pl-8 so the item lines up with checkbox/radio rows. |
variant | "default" | "destructive" | "default" | destructive switches text and icon color to the destructive token. |
disabled | boolean | false | Disables interaction; renders at 50% opacity. |
<DropdownMenuCheckboxItem>
| Prop | Type | Default | Description |
|---|---|---|---|
checked | boolean | "indeterminate" | - | Controlled checked state. |
onCheckedChange | (checked: boolean) => void | - | Fired when toggled. |
Renders an absolute-positioned check icon on the left when checked.
<DropdownMenuRadioGroup> + <DropdownMenuRadioItem>
Pair a group with one or more radio items. The group owns the value and onValueChange. Each radio item renders an auto-positioned bullet when selected.
<DropdownMenuLabel>
Non-interactive section heading.
| Prop | Type | Default | Description |
|---|---|---|---|
inset | boolean | false | Adds pl-8 for alignment with check/radio rows. |
<DropdownMenuSeparator>
Thin bg-border divider with negative margin so it spans the menu padding.
<DropdownMenuShortcut>
A right-aligned <span> for keyboard hints (⌘C, ⇧⌫). Pure layout helper; no Radix logic.
<DropdownMenuSub> + <DropdownMenuSubTrigger> + <DropdownMenuSubContent>
Nested submenu. Sub-trigger renders an auto-positioned chevron on the right. Sub-content opens to the side of the trigger.
<DropdownMenuPortal>, <DropdownMenuGroup>
Pass-throughs over the Radix primitives with data-slot attributes.
Composition
<DropdownMenu>owns the open/close state.<DropdownMenuTrigger asChild>wraps aButtonor icon button.<DropdownMenuContent>mounts via Portal anchored to the trigger.- Inside content: group items with
DropdownMenuGroup, label sections withDropdownMenuLabel, divide withDropdownMenuSeparator. - Shortcuts sit at the right edge via
DropdownMenuShortcut. - Submenus wrap nested
DropdownMenuSubblocks.
Variations
Items with shortcuts and destructive action
The canonical row-actions menu. Note the right-aligned shortcuts and the destructive variant for delete.
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="ghost" size="icon" aria-label="Row actions">
<MoreHorizontalIcon />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuItem>
<PencilIcon /> Edit
<DropdownMenuShortcut>⌘E</DropdownMenuShortcut>
</DropdownMenuItem>
<DropdownMenuItem>
<CopyIcon /> Duplicate
<DropdownMenuShortcut>⌘D</DropdownMenuShortcut>
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem variant="destructive">
<Trash2Icon /> Delete
<DropdownMenuShortcut>⌫</DropdownMenuShortcut>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>Checkbox items
Toggle visible columns or filters without closing the menu.
<DropdownMenuContent>
<DropdownMenuLabel>Toggle columns</DropdownMenuLabel>
<DropdownMenuSeparator />
<DropdownMenuCheckboxItem
checked={cols.name}
onCheckedChange={toggle('name')}
>
Name
</DropdownMenuCheckboxItem>
<DropdownMenuCheckboxItem
checked={cols.email}
onCheckedChange={toggle('email')}
>
Email
</DropdownMenuCheckboxItem>
</DropdownMenuContent>Submenu
Nest secondary actions inside a sub-trigger.
<DropdownMenuContent>
<DropdownMenuItem>Open</DropdownMenuItem>
<DropdownMenuSub>
<DropdownMenuSubTrigger>Share</DropdownMenuSubTrigger>
<DropdownMenuSubContent>
<DropdownMenuItem>Copy link</DropdownMenuItem>
<DropdownMenuItem>Email</DropdownMenuItem>
<DropdownMenuItem>Embed</DropdownMenuItem>
</DropdownMenuSubContent>
</DropdownMenuSub>
</DropdownMenuContent>Accessibility
- Role:
role="menu"on content,role="menuitem"on items,role="menuitemcheckbox"androle="menuitemradio"on stateful variants. - Keyboard: arrow keys navigate;
EnterandSpaceactivate; type-ahead jumps to items starting with the typed letter;Esccloses;Tabcloses and continues page focus. - Submenus:
→opens,←closes. - Focus management: focus moves into the menu on open and returns to the trigger on close.
aria-expandedis set on the trigger automatically;aria-controlslinks to the content id.- Destructive variant: visual cue only; pair with confirmation (
AlertDialog) if the action is irreversible. - Reduced motion: open/close animations honor
prefers-reduced-motion.
Related
- Context Menu - same compound, triggered by right-click on a region.
- Select - value-led picker (countries, status), not actions.
- Popover - generic anchored overlay when items don't follow menu semantics.
- Command - searchable command list for power users.