# ContextMenu

> A styleable right-click menu — a native popover at the cursor over a target; closes on outside click, Escape, or scroll.

URL: https://apogee.avaui.dev/docs/context-menu
Last updated: 2026-10-15

A styleable right-click menu — a native popover at the cursor over a target; closes on outside click, Escape, or scroll.

Last updated October 15, 2026

Uses JavaScript

Opens a native popover at the cursor on right-click (top layer), moves focus to the first item, wires the arrow keys, closes on item activation and on scroll or resize. Outside click and Escape are the browser’s own light dismiss.

**Without JS:** The panel stays hidden and the target's normal browser right-click menu opens instead — nothing is broken or lost.

```astro
<ContextMenu class="w-full">
<div class="grid h-24 w-full place-items-center rounded-md border border-dashed border-neutral text-sm text-neutral-faded">
  Right-click here
</div>
<DropdownItem slot="menu">Cut</DropdownItem>
<DropdownItem slot="menu">Copy</DropdownItem>
<DropdownItem slot="menu">Paste</DropdownItem>
</ContextMenu>
```

Items accept `indicator="check" | "checkbox" | "radio"` like [Dropdown](https://apogee.avaui.dev/docs/dropdown#indicators).

## Add

```sh
npx @ava-ui/apogee add context-menu
```

No Apogee dependencies. Pair with `DropdownItem` for menu entries.

## Usage

```astro
---
import ContextMenu from '@/components/apogee/ContextMenu/ContextMenu.astro'
import DropdownItem from '@/components/apogee/Dropdown/DropdownItem.astro'
---
<ContextMenu>
  <div>Right-click target</div>
  <DropdownItem slot="menu">Copy</DropdownItem>
  <DropdownItem slot="menu">Paste</DropdownItem>
</ContextMenu>
```

## Anatomy

-   **Target** — default slot; the element(s) that trigger the menu on right-click.
-   **Menu panel** — `slot="menu"`; a `role="menu"` popover placed at the cursor, in the top layer (no ancestor can clip it). Fill it with `DropdownItem`s (`role="menuitem"`).

## API

`@composable` — exposed to Content Editors in AVA. Any other attribute passes through to the root `<div>`.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `class` | `string` | — | Extra classes on the root wrapper, merged last. |

## States

-   **Closed** (default) — the popover is closed.
-   **Open** — right-click (or the keyboard context-menu key / Shift+F10) shows the panel at the cursor, clamped inside the viewport. Try it in the hero preview above.
-   **No JS** — a closed popover renders nothing; the browser’s native context menu opens instead.

## Examples

With leading icons:

```astro
<ContextMenu>
<div class="grid h-24 w-full place-items-center rounded-md border border-dashed border-neutral text-sm text-neutral-faded">
  Right-click here
</div>
<DropdownItem slot="menu"><Scissors /> Cut</DropdownItem>
<DropdownItem slot="menu"><Copy /> Copy</DropdownItem>
<DropdownItem slot="menu"><ClipboardPaste /> Paste</DropdownItem>
</ContextMenu>
```

## Events

The panel dispatches `apogee:contextmenu-open` (`detail: { x, y }`, the clamped position) and `apogee:contextmenu-close`, both bubbling, alongside the native `toggle` event.

## Accessibility

| Key | Action |
| --- | --- |
| Context-menu key, `Shift` `F10` | Opens the menu and focuses the first item. |
| `↓` `↑` | Move between items; wraps. |
| `Home` `End` | First / last item. |
| `Enter` `Space` | Activate the focused item and close the menu. |
| `Esc` | Closes the menu and returns focus. |

-   The panel has `role="menu"`; give items `role="menuitem"` (what `DropdownItem` renders).
-   **No JS** — the panel never opens; the browser’s native context menu opens instead, so the actions remain reachable through it.

## Tokens

| Token | Used for |
| --- | --- |
| `--border-neutral` | Panel border |
| `--background-elevation-overlay` | Panel background |
| `--duration-fast` / `--ease-standard` | Panel open fade/scale animation |

## Do / Don’t

-   **Do** keep items short and task-focused (Cut, Copy, Paste, Delete).
-   **Do** offer the same actions somewhere else too (a toolbar, a keyboard shortcut) — right-click alone isn’t discoverable for every user.
-   **Don’t** nest anything but menu items (`DropdownItem`) in the panel.
-   **Don’t** treat it as the only way to reach an action — no-JS visitors fall back to the native menu, which won’t show your custom entries.

## Content

-   Item labels are short verbs (Cut, Copy, Paste, Delete), sentence case, no ending punctuation — same rules as `DropdownItem`.

## Related

[

DropdownA menu on the native Popover API — the trigger opens a list of DropdownItems in the top layer, with sections and submenus.

](https://apogee.avaui.dev/docs/dropdown)[

MenubarA desktop-style app menubar (File, Edit, View…) with keyboard navigation between menus.

](https://apogee.avaui.dev/docs/menubar)[

PopoverRich content on click, built on the native Popover API — top layer and light dismiss for free, anchored with CSS anchor positioning.

](https://apogee.avaui.dev/docs/popover)
