# ContextMenu

> A menu that opens at the pointer on right-click, long-press, Shift+F10 or the Menu key.

Category: Overlays · Status: stable · Package: @bindshq/stance-react@0.1.1 · Docs: https://stanceui.com/components/context-menu

Use ContextMenu for shortcuts to actions on a specific object, such as a block in the signature editor or a row in a document list. Every action in a context menu must also be reachable another way (a toolbar or ActionMenu), because context menus are hard to discover. It shares its item parts and keyboard model with DropdownMenu.

## Import

```tsx
import { ContextMenu, ContextMenuTrigger, ContextMenuContent, ContextMenuItem, ContextMenuCheckboxItem, ContextMenuSeparator, ContextMenuShortcut, ContextMenuSub, ContextMenuSubTrigger, ContextMenuSubContent } from '@bindshq/stance-react';
```

Styles are imported once per app: `@bindshq/stance-tokens/css` and `@bindshq/stance-react/styles.css`.

## Examples

### Basic

Right-click the area, long-press on touch, or focus it and press Shift+F10.

```tsx
import * as React from 'react';
import { ContextMenu, ContextMenuContent, ContextMenuItem, ContextMenuSeparator, ContextMenuTrigger } from '@bindshq/stance-react';

const area: React.CSSProperties = {
  display: 'grid',
  placeItems: 'center',
  width: 'min(100%, 360px)',
  height: 160,
  border: '1px dashed var(--st-color-border-strong)',
  borderRadius: 'var(--st-radius-lg)',
  color: 'var(--st-color-fg-muted)',
  fontSize: 'var(--st-font-size-sm)',
  textAlign: 'center',
  padding: 16,
};

export function Basic() {
  return (
    <ContextMenu>
      <ContextMenuTrigger tabIndex={0} aria-label="Signature block: logo" style={area}>
        Right-click the logo block
      </ContextMenuTrigger>
      <ContextMenuContent aria-label="Block actions">
        <ContextMenuItem>Replace image</ContextMenuItem>
        <ContextMenuItem>Edit link</ContextMenuItem>
        <ContextMenuItem>Duplicate block</ContextMenuItem>
        <ContextMenuSeparator />
        <ContextMenuItem destructive>Remove block</ContextMenuItem>
      </ContextMenuContent>
    </ContextMenu>
  );
}
```

### Icons, shortcuts and submenus

```tsx
import * as React from 'react';
import { ContextMenu, ContextMenuContent, ContextMenuItem, ContextMenuSeparator, ContextMenuShortcut, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger, Icon } from '@bindshq/stance-react';

const area: React.CSSProperties = {
  display: 'grid',
  placeItems: 'center',
  width: 'min(100%, 360px)',
  height: 160,
  border: '1px dashed var(--st-color-border-strong)',
  borderRadius: 'var(--st-radius-lg)',
  color: 'var(--st-color-fg-muted)',
  fontSize: 'var(--st-font-size-sm)',
  textAlign: 'center',
  padding: 16,
};

export function WithSubmenu() {
  return (
    <ContextMenu>
      <ContextMenuTrigger
        tabIndex={0}
        aria-label="Contract: Master services agreement"
        style={area}
      >
        Master services agreement.pdf
      </ContextMenuTrigger>
      <ContextMenuContent aria-label="Document actions">
        <ContextMenuItem icon={<Icon name="eye" />}>
          Open <ContextMenuShortcut>↵</ContextMenuShortcut>
        </ContextMenuItem>
        <ContextMenuItem icon={<Icon name="pencil" />}>
          Rename <ContextMenuShortcut>F2</ContextMenuShortcut>
        </ContextMenuItem>
        <ContextMenuSub>
          <ContextMenuSubTrigger icon={<Icon name="folder" />}>Move to</ContextMenuSubTrigger>
          <ContextMenuSubContent>
            <ContextMenuItem>Contracts / 2026</ContextMenuItem>
            <ContextMenuItem>Contracts / Archive</ContextMenuItem>
            <ContextMenuItem>Shared with Legal</ContextMenuItem>
          </ContextMenuSubContent>
        </ContextMenuSub>
        <ContextMenuItem icon={<Icon name="download" />}>Download</ContextMenuItem>
        <ContextMenuSeparator />
        <ContextMenuItem icon={<Icon name="trash" />} destructive>
          Delete
        </ContextMenuItem>
      </ContextMenuContent>
    </ContextMenu>
  );
}
```

### Checkable items

```tsx
import * as React from 'react';
import { ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuTrigger } from '@bindshq/stance-react';

const area: React.CSSProperties = {
  display: 'grid',
  placeItems: 'center',
  width: 'min(100%, 360px)',
  height: 160,
  border: '1px dashed var(--st-color-border-strong)',
  borderRadius: 'var(--st-radius-lg)',
  color: 'var(--st-color-fg-muted)',
  fontSize: 'var(--st-font-size-sm)',
  textAlign: 'center',
  padding: 16,
};

export function Toggles() {
  const [grid, setGrid] = React.useState(true);
  const [guides, setGuides] = React.useState(false);
  return (
    <ContextMenu>
      <ContextMenuTrigger tabIndex={0} aria-label="Editor canvas" style={area}>
        Editor canvas, right-click for view options
      </ContextMenuTrigger>
      <ContextMenuContent aria-label="View options">
        <ContextMenuCheckboxItem checked={grid} onCheckedChange={setGrid}>
          Show grid
        </ContextMenuCheckboxItem>
        <ContextMenuCheckboxItem checked={guides} onCheckedChange={setGuides}>
          Show safe-area guides
        </ContextMenuCheckboxItem>
      </ContextMenuContent>
    </ContextMenu>
  );
}
```

## API reference

| Component | Prop | Type | Default | Description |
| --- | --- | --- | --- | --- |
| ContextMenu | `open / defaultOpen` | `boolean` | None | Controlled or initial open state. |
| ContextMenu | `onOpenChange` | `(open: boolean) => void` | None | Called when the menu opens or closes. |
| ContextMenu | `disabled` | `boolean` | `false` | Let the native browser menu show instead. |
| ContextMenuTrigger | `asChild` | `boolean` | `false` | Use your own element as the target area. |
| ContextMenuTrigger | `longPressDelay` | `number` | `500` | Touch long-press duration in ms. Moving more than 8px cancels. |
| ContextMenuTrigger | `tabIndex` | `number` | None | Make the area focusable so keyboard users can open it with Shift+F10. |
| ContextMenuContent | `aria-label` | `string` | `'Context menu'` | Accessible name of the menu, e.g. “Block actions”. |
| ContextMenuContent | `loop / onEscapeKeyDown` | `boolean / function` | None | As DropdownMenuContent. |
| ContextMenuItem | `onSelect, icon, destructive, disabled, closeOnSelect` | `None` | None | Identical to DropdownMenuItem. |
| ContextMenuCheckboxItem / RadioItem / Sub… | `None` | `None` | None | Identical to their DropdownMenu counterparts. |

## Accessibility

- Opens from the keyboard with Shift+F10 or the ContextMenu key while focus is inside the trigger area.
- The menu is positioned at the pointer (or the focused element for keyboard) and receives focus on open.
- Focus returns to the element that had it before the menu opened.
- Long-press support makes the menu usable on touch screens; the browser callout is suppressed.
- Provide every action elsewhere too. Context menus are not discoverable.

## Keyboard

| Keys | Action |
| --- | --- |
| `Shift+F10` `ContextMenu` | Open the menu from a focused element in the area. |
| `ArrowDown` `ArrowUp` `Home` `End` | Move between items. |
| `Enter` `Space` | Activate the focused item. |
| `ArrowRight` `ArrowLeft` | Open or close a submenu. |
| `Escape` | Close and restore focus. |

## Guidelines

**Do**

- Mirror the actions in a visible toolbar or ActionMenu.
- Keep the most frequent action first.

**Don’t**

- Hide critical or unique functionality only in a context menu.
- Override the browser menu on text the user may want to copy.

## Related

- https://stanceui.com/components/dropdown-menu
- https://stanceui.com/components/action-menu
