# ContextMenu The menu a right-click opens. - Group: Overlays - Import: `import { ContextMenu } from '@misoto22/folio'` - Page: https://ui.misoto22.com/components/context-menu/ - Related: dropdown-menu ## When to reach for it Never as the only way to reach an action. Touch users, trackpad users and keyboard users may have no way to open it. ## Anatomy - **Trigger** (required) — The region a secondary click opens the menu over. Radix wraps children in its own inline span unless you pass asChild, and sets -webkit-touch-callout: none on it so the OS text callout does not fire first. - **Panel** (required) — The portalled menu, placed at the POINTER rather than against the trigger — there is no side or align to set here, only the 8px collision padding that keeps it inside the viewport or the OverlayContainer frame. - **Item** — A row, taking the same icon, destructive and disabled props as DropdownMenuItem — icon in either spelling — and highlighting on the same data-highlighted. - **Label** — A mono eyebrow, on its own, and visual only. ContextMenuGroup is the one that heads rows: it renders role="group" and points its aria-labelledby at this. - **Group** — A named section: role="group" around the rows, with label rendered inside it as the Label and named through aria-labelledby. - **Separator** — A hairline between groups, as a real role="separator". ## Best practices ### Do - Pass asChild and hand it the element itself: without it Radix inserts a span between you and your child, and that span becomes the flex or grid item while your card is laid out inside it as inline content. - Build the same array of actions into a DropdownMenu behind an overflow button — the two take identical icon, destructive and disabled props, so one list feeds both and the right-click becomes the shortcut rather than the only door. - Wrap the subtree in OverlayContainer when the right-clickable region lives in a scrolling or bounded frame: this is the one panel whose position the reader personally chose, and a flip against a viewport edge they cannot see lands it somewhere they did not point. ### Don’t - Do not read “no touch support” as the whole story: Radix opens the menu on a 700ms long press for touch and pen, but cancels the moment the pointer moves — so on a scrollable list the long press and the scroll gesture compete and the scroll usually wins. - A bare ContextMenuLabel over rows is a picture of a heading: Radix’s MenuLabel is a plain div with no role and nothing tying it to what follows, so the sections a sighted reader sees arrive as one undivided list. ContextMenuGroup renders both halves and wires them together. - Radix defaults modal to true here too, so the page behind is scroll-locked and pointer-inert while the menu is open — a right-click menu over a long list stops the list moving under it, which is right for a short action list and wrong for anything the reader must scroll to answer. ## Keyboard - Shift / F10 — Opens the menu from the keyboard, where the platform supports it. - ↑ / ↓ — Moves between items. - Escape — Closes it. ## ContextMenu Re-export of `ContextMenuPrimitive.Root`. Radix ContextMenu root and trigger, as typed passthroughs. ## ContextMenuTrigger Re-export of `ContextMenuPrimitive.Trigger`. ## ContextMenuContent The menu a right-click opens. Never the only way to reach an action. A context menu is opened by a secondary pointer button or a keyboard's own menu key, and a meaningful share of readers have neither — a touch user, someone on a trackpad they have not configured, anyone driving the page by keyboard alone. Whatever is in here belongs somewhere reachable too: a row's overflow button, a toolbar. ## ContextMenuItem A row. Highlight follows `data-highlighted`, which covers hover and keyboard. ### Props - `icon` — `RemixiconComponentType | ReactNode`. Optional leading icon. Either spelling — `icon={Copy}` passes the component and this sizes it, `icon={}` passes the element and this places it. - `destructive` — `boolean` default `false`. Paints the row as destructive. Use for delete, revoke, disconnect. Also accepts: `ComponentProps`. ## ContextMenuSeparator Hairline divider between groups. ## ContextMenuLabel Mono eyebrow heading, on its own. Visual only: Radix renders it as a bare `
` with no role. Reach for `ContextMenuGroup` when the eyebrow is a HEADING over rows; this is right for a line that heads nothing. ## ContextMenuGroup A named section of a menu. The eyebrow alone was a picture of a heading: Radix's `MenuLabel` carries no role and no `aria-labelledby` wiring, so a sighted reader saw sections and a screen-reader user got one undifferentiated list. This renders the group, renders the label inside it, and points the one at the other. ### Props - `label` — `ReactNode`. The eyebrow over the rows, and the group's accessible name. Also accepts: `ComponentProps`. ## Example — on a region ```tsx
Right-click anywhere in this box
Frame Copy link Download original Delete
``` ## Example — two doors ```tsx
kyoto-february.tif {ACTIONS.map((action) => ( {action.label} ))}
{ACTIONS.map((action) => ( {action.label} ))}
``` ## Example — a card trigger ```tsx api.misoto22.com live Deployed from main four minutes ago. Right-click the card for its actions. Open the deployment Pin to the dashboard Roll back to the previous build ```