# ContextMenu

> A menu of actions for a region, opened at the pointer with a right-click, Shift+F10 or a long press.

Category: Overlays. Docs page: https://rime.mjsons.net/components/context-menu

## Installation

```bash
npx shadcn@latest add KezLahd/rime/context-menu
```

ContextMenu wraps a region (a row, a card, a file) and opens the shared menu list where the pointer is. The region is focusable, so keyboard users open it with Shift+F10 or the Menu key; on touch a long press (longPressMs, 500ms) opens it.

Items take an icon, a shortcut hint (display only), a danger tone and a disabled state; separators and headings group them. It is the same popover glass and item rhythm as Menu.

inline renders the open panel in the page flow: no portal, scrim, focus trap, scroll lock or outside-click listener. It exists for docs, previews and static mock-ups; never ship it as the live overlay.

## Usage

```tsx
import { ContextMenu } from "@/components/ui";

<ContextMenu label="Actions for Invoice INV-0042" items={[
  { id: "open", label: "Open", onSelect: open },
  { id: "rename", label: "Rename", shortcut: "F2", onSelect: rename },
  { id: "sep", separator: true },
  { id: "delete", label: "Move to bin", tone: "danger", onSelect: remove },
]}>
  Invoice INV-0042.pdf
</ContextMenu>
```

## Props: ContextMenu

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `children` (required) | `ReactNode` |  | The region that answers a right-click: a row, a card, a canvas. |
| `items` (required) | `ReadonlyArray<MenuListEntry>` |  | The menu: actions, separators ({ id, separator: true }) and headings ({ id, heading }). |
| `label` (required) | `string` |  | The menu's accessible name, e.g. "Actions for Invoice INV-0042". |
| `longPressMs` | `number` | `500` | ms a touch must be held to open it on phones and tablets. |
| `inline` | `boolean` |  | Render the menu open in the page flow, over the region (docs, previews). Nothing is interactive and no listeners are attached. |
| `highlightId` | `string` |  | Inline only: the item drawn in its hover state. |
| `className` | `string` |  |  |

## Examples

### Open

The menu over its region, drawn inline with one item highlighted.

```tsx
<ContextMenu inline label="Actions for Invoice INV-0042" items={ITEMS} highlightId="rename">
  Invoice INV-0042.pdf
</ContextMenu>
```

### On a region

Right-click it, or focus it and press Shift F10.

```tsx
<ContextMenu label="Actions for Invoice INV-0042" items={ITEMS}>…</ContextMenu>
```

## Theme tokens

Per-component tokens. Undeclared by default: the default below is the fallback the CSS uses. Set any of them at :root or on a wrapper to restyle every instance.

| Token | Default |
| --- | --- |
| `--context-region-height` | `150px` |
| `--context-region-radius` | `var(--r-lg)` |
| `--context-region-width` | `300px` |
| `--menu-list-min-width` | `220px` |
| `--popover-item-active-bg` | `linear-gradient(to right, rgba(var(--rgb-brand), 0.14), rgba(var(--rgb-brand-deep), 0.07))` |
| `--popover-item-press-bg` | `linear-gradient(to right, rgba(var(--rgb-brand), 0.2), rgba(var(--rgb-brand-deep), 0.1))` |
| `--popover-item-radius` | `var(--r-xs)` |
| `--popover-pad` | `calc(6px * var(--density))` |
| `--popover-radius` | `var(--r-lg)` |

System tokens it reads: `--border-w`, `--danger-ink`, `--density`, `--dur`, `--dur-fast`, `--dur-slow`, `--ease`, `--ease-out`, `--focus-ring`, `--font-body`, `--ink-body`, `--ink-brand`, `--ink-disabled`, `--ink-muted`, `--line-input`, `--line-soft`, `--popover-blur`, `--popover-border`, `--popover-shadow`, `--popover-surface`, `--r-lg`, `--r-xs`, `--rgb-brand`, `--rgb-brand-deep`, `--rgb-danger`, `--rgb-white`, `--text-caption`, `--text-micro`, `--text-small`, `--tracking-label`, `--wash-subtle`, `--z-popover`.

## Accessibility

- The menu is role="menu" with role="menuitem" items: arrows, Home, End and typeahead move; Enter or Space runs; Esc closes and returns focus to the region; Tab closes.
- The region is focusable and opens on Shift+F10 and the Menu key, so a mouse is never required.
- Every action in a context menu must also be reachable some other way (a row Menu, a toolbar).

## Do

- Put destructive items last, after a separator.
- Keep it to the actions for that one thing.

## Don't

- Don't make it the only route to an action.
- Don't override the browser's menu on text people need to copy.

Related: https://rime.mjsons.net/components/menu, https://rime.mjsons.net/components/menubar
