Context menu
The actions for one thing, opened with a right-click, a long press or the keyboard. It is a shortcut, so every action in it also needs a visible way in.
Installation
Set up Camaleo once (Installation), then import the parts you need. The popup renders in a portal, at the pointer, and keeps the skin, mode and brand of the page around it.
import { ContextMenu, ContextMenuTrigger, ContextMenuContent, ContextMenuItem, ContextMenuCheckboxItem, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSub, ContextMenuSubTrigger, ContextMenuSubContent, ContextMenuGroup, ContextMenuGroupLabel, ContextMenuSeparator } from "@camaleo/react";Anatomy
ContextMenu holds the open state. ContextMenuTrigger (data-slot="context-menu-trigger") is the area people right-click; ContextMenuContent renders the popup below in a portal. Every part has a data-slot you can target from CSS.
Examples
Every example is a real file you can copy. They all wear the skin, mode and brand from the bar above, and they all start closed: right-click them.
On a file row
The classic use: the actions for one file, where the pointer already is. tabIndex={0} lets keyboard users focus the row and open the menu with Shift+F10 or the Menu key.
On a canvas
On an empty board there is nothing to put a button on, so the right-click is where people look. Keep the same commands in a toolbar.
Groups and separators
A ContextMenuGroupLabel over each group helps people scan a longer menu; the destructive group goes last.
With shortcuts
People who right-click are learning. Show the shortcut with Kbd and add aria-keyshortcuts, so next time they skip the menu.
Act, then announce
Right-click the note and pick an action. Focus goes back to the note, and a role="status" line says what happened.
Also in a visible menu
A context menu is hidden by nature. Put the same actions behind a "⋯" button, from one shared list, so touch, keyboard and screen reader users find them.
Checkbox and radio items
Right-click the board and change its settings: ContextMenuCheckboxItem and ContextMenuRadioItem keep the menu open and report aria-checked, so people can change several at once.
Submenu
Put a list of destinations behind one "Move to" item instead of stretching the menu; → opens it, ← goes back, and the current folder is disabled.
In context
A context menu speeds up work that already has a visible path. These are whole pieces of UI you can copy, in the skin you picked.
- Office lease 2027.pdf2.4 MB
- Budget 2027.xlsx860 KB
- Floor plan.png3.1 MB
Redesign the checkout page
Due Nov 12, 2026 · Rafael Moreira
The new checkout is on staging. Can someone test the coupon field before Friday?
Guidelines
The right-click is a shortcut for people who know it; the "⋯" button is the way in for everyone else.
Nothing on screen says they exist, and on a phone or with a screen reader nobody finds them.
Right-click a comment: reply, edit, copy. The menu answers "what can I do with this?".
Settings and Sign out have nothing to do with the comment, and they belong in the header where people expect them.
Props
danger colors a destructive action. Put it last, after a separator.<a> for a link.These are the props of ContextMenuItem. ContextMenu takes Base UI's root props: open, onOpenChange, disabled and actionsRef. ContextMenuCheckboxItem takes checked, defaultChecked, onCheckedChange and shortcut; ContextMenuRadioGroup takes value, defaultValue and onValueChange, and each ContextMenuRadioItem a value. Wrap a ContextMenuSubTrigger and its ContextMenuSubContent in a ContextMenuSub. ContextMenuTrigger renders a <div>: give it tabIndex={0} so it can be focused, or render to use another element.
Styling hooks
Restyle it without forking: target the attributes, or set the tokens on a parent, a skin or the popup itself.
Attributes
Tokens it reads
Color
Shape & size
Type & motion
This component only
Accessibility
- Nothing on screen says a context menu exists. Every action in it must also be reachable from a visible button or menu.
- Items are menuitem; checkbox items are menuitemcheckbox and radio items menuitemradio, both with aria-checked. A submenu trigger reports aria-haspopup and aria-expanded.
- The trigger is a <div>: add tabIndex={0} so keyboard users can focus it and open the menu with Shift+F10 or the Menu key. Rows that already have a "⋯" button can skip it and save a tab stop.
- On touch screens a long press opens it; screen reader users rarely find it, which is one more reason for the visible path.
- The popup is portalled but keeps the skin through PortalScope, and contrast passes WCAG 2.2 AA in all 13 skins.