Skip to main content
Gremorie

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

Extends Radix DropdownMenu.Root. Standard controlled API (open, defaultOpen, onOpenChange, modal).

Extends Radix DropdownMenu.Trigger. Use asChild to forward styles to a Button or any custom trigger.

PropTypeDefaultDescription
sideOffsetnumber4Pixel 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].

PropTypeDefaultDescription
insetbooleanfalseAdds 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.
disabledbooleanfalseDisables interaction; renders at 50% opacity.
PropTypeDefaultDescription
checkedboolean | "indeterminate"-Controlled checked state.
onCheckedChange(checked: boolean) => void-Fired when toggled.

Renders an absolute-positioned check icon on the left when checked.

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.

Non-interactive section heading.

PropTypeDefaultDescription
insetbooleanfalseAdds pl-8 for alignment with check/radio rows.

Thin bg-border divider with negative margin so it spans the menu padding.

A right-aligned <span> for keyboard hints (⌘C, ⇧⌫). Pure layout helper; no Radix logic.

Nested submenu. Sub-trigger renders an auto-positioned chevron on the right. Sub-content opens to the side of the trigger.

Pass-throughs over the Radix primitives with data-slot attributes.

Composition

  1. <DropdownMenu> owns the open/close state.
  2. <DropdownMenuTrigger asChild> wraps a Button or icon button.
  3. <DropdownMenuContent> mounts via Portal anchored to the trigger.
  4. Inside content: group items with DropdownMenuGroup, label sections with DropdownMenuLabel, divide with DropdownMenuSeparator.
  5. Shortcuts sit at the right edge via DropdownMenuShortcut.
  6. Submenus wrap nested DropdownMenuSub blocks.

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>

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" and role="menuitemradio" on stateful variants.
  • Keyboard: arrow keys navigate; Enter and Space activate; type-ahead jumps to items starting with the typed letter; Esc closes; Tab closes and continues page focus.
  • Submenus: opens, closes.
  • Focus management: focus moves into the menu on open and returns to the trigger on close.
  • aria-expanded is set on the trigger automatically; aria-controls links 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.
  • 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.

On this page