Source: https://monarchui.dev/components/dropdown-menu/

Components · Overlays

# DropdownMenu

Action menu with checkbox, radio and nested items.

@rookcom/monarch-react

Component

## Actions

## Usage examples

### Destructive item with icons

## Purpose

A list of actions or options that opens from a trigger button.

### Use when

- Several related actions behind one button ("Actions", "…").

### Avoid when

- Choosing a form value: use Select or Combobox.

## Design principles

- `tone="danger"` for destructive items, paired with a confirmation step (ConfirmDialog). The whole item, icon included, takes the danger colour, so the tone does not rely on the label alone.
- Destructive items go last, after a separator, so they are not hit by accident.
- Shortcut hints are display only; the app binds the keys.

## API reference

```tsx
import { DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger } from '@rookcom/monarch-react';
```

| Export | Kind | Rendering | Root class |
| --- | --- | --- | --- |
| `DropdownMenu` | component | client | `.mn-menu` |
| `DropdownMenuCheckboxItem` | component | client | `.mn-menu` |
| `DropdownMenuContent` | component | client | `.mn-menu` |
| `DropdownMenuGroup` | component | client | `.mn-menu` |
| `DropdownMenuItem` | component | client | `.mn-menu` |
| `DropdownMenuLabel` | component | client | `.mn-menu` |
| `DropdownMenuRadioGroup` | component | client | `.mn-menu` |
| `DropdownMenuRadioItem` | component | client | `.mn-menu` |
| `DropdownMenuSeparator` | component | client | `.mn-menu` |
| `DropdownMenuSub` | component | client | `.mn-menu` |
| `DropdownMenuSubContent` | component | client | `.mn-menu` |
| `DropdownMenuSubTrigger` | component | client | `.mn-menu` |
| `DropdownMenuTrigger` | component | client | `.mn-menu` |

Root, Trigger, Group, RadioGroup and Sub are the Radix DropdownMenu parts.

Content defaults to `align="start"` and `sideOffset={4}` and renders in a portal.

With `asChild`, DropdownMenuItem renders its child (for example a link) and ignores `icon` and `shortcut`.

Generated from the TypeScript declarations of `packages/react/src/components/overlays/dropdown-menu`.

## Properties

### `DropdownMenu`

Action menu. Arrow keys move, typeahead jumps, Escape closes and restores focus.

| Prop | Type | Description |
| --- | --- | --- |
| `children` | `React.ReactNode` |  |

### `DropdownMenuCheckboxItem`

| Prop | Type | Description |
| --- | --- | --- |
| `asChild` | `boolean` |  |
| `children` | `ReactNode` |  |
| `className` | `string` |  |
| `disabled` | `boolean` |  |
| `id` | `string` |  |

### `DropdownMenuContent`

| Prop | Type | Description |
| --- | --- | --- |
| `asChild` | `boolean` |  |
| `children` | `ReactNode` |  |
| `className` | `string` |  |
| `id` | `string` |  |

### `DropdownMenuGroup`

| Prop | Type | Description |
| --- | --- | --- |
| `asChild` | `boolean` |  |
| `children` | `ReactNode` |  |
| `className` | `string` |  |
| `id` | `string` |  |

### `DropdownMenuItem`

| Prop | Type | Description |
| --- | --- | --- |
| `asChild` | `boolean` |  |
| `children` | `ReactNode` |  |
| `className` | `string` |  |
| `disabled` | `boolean` |  |
| `icon` | `ReactNode` |  |
| `id` | `string` |  |
| `shortcut` | `string` | Keyboard shortcut hint, e.g. "⌘D". Display only. |
| `tone` | `"danger" \| "default"` | `danger` for destructive actions. Pair with a confirmation step. |

### `DropdownMenuLabel`

| Prop | Type | Description |
| --- | --- | --- |
| `asChild` | `boolean` |  |
| `children` | `ReactNode` |  |
| `className` | `string` |  |
| `id` | `string` |  |

### `DropdownMenuRadioGroup`

| Prop | Type | Description |
| --- | --- | --- |
| `asChild` | `boolean` |  |
| `children` | `ReactNode` |  |
| `className` | `string` |  |
| `id` | `string` |  |

### `DropdownMenuRadioItem`

| Prop | Type | Description |
| --- | --- | --- |
| `asChild` | `boolean` |  |
| `children` | `ReactNode` |  |
| `className` | `string` |  |
| `disabled` | `boolean` |  |
| `id` | `string` |  |

### `DropdownMenuSeparator`

| Prop | Type | Description |
| --- | --- | --- |
| `asChild` | `boolean` |  |
| `children` | `ReactNode` |  |
| `className` | `string` |  |
| `id` | `string` |  |

### `DropdownMenuSub`

| Prop | Type | Description |
| --- | --- | --- |
| `children` | `React.ReactNode` |  |

### `DropdownMenuSubContent`

| Prop | Type | Description |
| --- | --- | --- |
| `asChild` | `boolean` |  |
| `children` | `ReactNode` |  |
| `className` | `string` |  |
| `id` | `string` |  |

### `DropdownMenuSubTrigger`

| Prop | Type | Description |
| --- | --- | --- |
| `asChild` | `boolean` |  |
| `children` | `ReactNode` |  |
| `className` | `string` |  |
| `disabled` | `boolean` |  |
| `id` | `string` |  |

### `DropdownMenuTrigger`

| Prop | Type | Description |
| --- | --- | --- |
| `asChild` | `boolean` |  |
| `children` | `ReactNode` |  |
| `className` | `string` |  |
| `disabled` | `boolean` |  |
| `id` | `string` |  |

## Variants

| Prop | Values | Description |
| --- | --- | --- |
| `tone (DropdownMenuItem)` | `'default'``'danger'` | Exposed as `data-tone`. `danger` colours the label and icon with the danger text token and highlights with the danger surface. |

## States

| State | Exposed as | Behaviour |
| --- | --- | --- |
| Highlighted | `data-highlighted` | Item under focus or pointer. |
| Disabled | `data-disabled` | Skipped by keyboard navigation. |
| Checked | – | Checkbox and radio items show a check or dot indicator. |

## Interaction behaviour

- Selecting an item calls `onSelect` and closes the menu.
- Sub-menus open from DropdownMenuSubTrigger.
- To confirm a destructive item, open a ConfirmDialog from its `onSelect`; the menu closes first and the dialog returns focus to the menu trigger.
- Controlled with `open` + `onOpenChange`, or uncontrolled (`defaultOpen`).

## Keyboard support

| Keys | Action |
| --- | --- |
| Enter / Space / ArrowDown | On the trigger, opens the menu and focuses the first item. |
| ArrowDown / ArrowUp | Moves between items. |
| Typeahead | Jumps to the item starting with the typed text. |
| ArrowRight / ArrowLeft | Opens or closes a sub-menu. |
| Enter | Selects the focused item. |
| Escape | Closes the menu and restores focus to the trigger. |

## Accessibility

Role

menu, menuitem, menuitemcheckbox, menuitemradio

Accessible name

The trigger’s label.

- Item icons and shortcut hints are `aria-hidden`.
- A destructive item is not announced as such by tone alone: name the action clearly ("Delete ticket").

## Responsive behaviour

- Menus are at least 12rem and at most `min(22rem, 100vw - 2rem)` wide, so they fit a 320px screen.
- Radix flips the menu to the other side and shifts it along the edge when it would leave the viewport (`avoidCollisions`, on by default); pass `collisionPadding` to keep a margin.
- Items are at least `--mn-control-sm` tall.

## Theme support

- Styles are the shared `.mn-menu` rules in styles/menu.css (also used by Select and Combobox); semantic tokens only.

## Do and don't

### Do

- Label the trigger with what the menu is about.
- Group items with labels and separators.

### Don't

- Do not put form inputs inside a menu.
- Do not rely on the shortcut hint to bind keys.
- Do not run an irreversible action straight from a menu item without a confirmation.

## Related components

- [Select](https://monarchui.dev/components/select/): Choosing one value for a form field.
- [Popover](https://monarchui.dev/components/popover/): Arbitrary floating content.
- [Breadcrumb](https://monarchui.dev/components/breadcrumb/): Uses a DropdownMenu for collapsed levels.
- [ConfirmDialog](https://monarchui.dev/components/confirm-dialog/): The confirmation step for a destructive item.

## Dependencies

| Kind | Depends on |
| --- | --- |
| npm packages | `@radix-ui/react-dropdown-menu``react` |
| Monarch components | None |

## Testing coverage

- Opens from the keyboard and focuses the first item; ArrowDown moves; Enter selects and closes.
- No axe violations in the open menu (jsdom).
- Destructive items expose `data-tone="danger"`, hide their icon from assistive technology, are reached with End and selected with Enter.
- Renders on the server (closed).

| Check | Covered |
| --- | --- |
| Axe in jsdom | Yes |
| Server rendering | Yes |
| Browser suites | Visual baselines: gallery/dropdown-menu, overlays/menu-light (open) and overlays/menu-danger-light-390 (open, phone width); Cross-browser axe: /components/dropdown-menu |

Tests: `packages/react/src/components/overlays/dropdown-menu`

## All example code

### Actions

```tsx
import { Button, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger } from '@rookcom/monarch-react';

// MoreIcon: demo icon from the docs site; use your own.

<DropdownMenu>
  <DropdownMenuTrigger asChild>
    <Button trailingIcon={<MoreIcon />}>Actions</Button>
  </DropdownMenuTrigger>
  <DropdownMenuContent>
    <DropdownMenuLabel>Ticket</DropdownMenuLabel>
    <DropdownMenuItem shortcut="R">Rename</DropdownMenuItem>
    <DropdownMenuItem>Assign to me</DropdownMenuItem>
    <DropdownMenuCheckboxItem checked>Watching</DropdownMenuCheckboxItem>
    <DropdownMenuSeparator />
    <DropdownMenuItem tone="danger">Delete</DropdownMenuItem>
  </DropdownMenuContent>
</DropdownMenu>
```

### Destructive item with icons

```tsx
import { Button, DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger } from '@rookcom/monarch-react';

// PencilIcon, TrashIcon: demo icons from the docs site; use your own.

<DropdownMenu>
  <DropdownMenuTrigger asChild>
    <Button>Document</Button>
  </DropdownMenuTrigger>
  <DropdownMenuContent>
    <DropdownMenuItem icon={<PencilIcon />} shortcut="E">
      Edit
    </DropdownMenuItem>
    <DropdownMenuSeparator />
    <DropdownMenuItem tone="danger" icon={<TrashIcon />}>
      Move to trash
    </DropdownMenuItem>
  </DropdownMenuContent>
</DropdownMenu>
```
