// preview in
saved for every page

Menu

A list of actions that opens from a button. Use it to tuck away secondary actions on a row, a card or a toolbar, not to navigate or to pick a value.

Built on Base UIPattern WAI-ARIA Menu ButtonClient componentSource ↗

Installation

Set up Camaleo once (Installation), then import the parts you need. The popup renders in a portal and keeps the skin, mode and brand of the page around it.

import { Menu, MenuTrigger, MenuContent, MenuItem, MenuCheckboxItem, MenuRadioGroup, MenuRadioItem, MenuSub, MenuSubTrigger, MenuSubContent, MenuGroup, MenuGroupLabel, MenuSeparator } from "@camaleo/react";

Anatomy

Menu holds the open state. MenuTrigger is the button (data-slot="menu-trigger", or the Button's own slot when you pass render={<Button />}); MenuContent 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.

minimal · light · #3fa34d

With shortcuts

Show the shortcut with Kbd so people learn it while they use the menu, and add aria-keyshortcuts so screen readers say it too. The menu only displays it: wire the keys yourself.

Groups and separators

Past five or six items, a MenuGroupLabel over each group lets people skip to the right part instead of reading every row.

Showing: Gridlines, Snap to grid

Checkbox items

Turn options on and off. MenuCheckboxItem stays open after a click and reports aria-checked, so screen readers say "checked" or "not checked".

Act, then announce

Pick an action. Focus goes back to the trigger, and a role="status" line tells screen readers what happened, because the menu that showed it is gone.

Destructive, with a confirm

Pick "Delete project". It comes last, after a separator, and opens an AlertDialog; finalFocus brings focus back to the menu button when it closes.

Disabled, with a reason

Keep an unavailable action in the menu so people learn it exists, and say why in the item itself: the reason is read with its name.

Icon-only trigger

A "⋯" button has no text, so its aria-label says what the actions are for: "Actions for invoice INV-4029", not just "More".

Links as items

For a few related pages, like a help menu, give an item render={<a href="…" />}: it opens with Enter, and the browser can open it in a new tab.

Showing: List · Name

Radio items and a submenu

For a view setting with one choice, like list or grid, use MenuRadioItem; tuck a longer group, like the sort order, into a MenuSub that → opens and ← closes.

In context

Menus keep the secondary actions out of the way. These are whole pieces of UI you can copy, in the skin you picked.

InvoiceClientStatusAmountActions
INV-4029Northwind TradersPaid$4,250.00
INV-4028Blue Harbor CaféPending$1,180.50
INV-4027Lumen StudioPending$12,900.00
Row actionsTable · Badge · IconButton · Menu
Acme Design
Account menuAvatar · Button · Menu
Signed

Office lease 2027.pdf

2.4 MB · Edited Oct 14, 2026

File cardCard · Badge · IconButton · Menu

Guidelines

DoShort labels that start with a verb.

"Rename", "Duplicate", "Move to folder…": people know what each item does before they pick it.

Don’tA menu to pick a value.

After the click the trigger still says "Country", and the form gets nothing. Use a Select; to move between pages, use links or a NavigationMenu.

DoDestructive actions last, after a separator.

The red item is out of the way of a quick ↓ Enter, and its color says it is different.

Don’tDelete between everyday actions.

One slip of the pointer or the arrow keys and the wrong thing is gone.

Props

PropTypeDefaultDescription
iconReactNode—Icon before the label. Hidden from screen readers; some skins hide menu icons altogether.
shortcutReactNode—Shown at the end, e.g. "Ctrl E". Display only: wire the shortcut yourself.
tone"danger"—danger colors a destructive action. Put it last, after a separator.
renderReactElement | (props, state) => ReactElement—Renders another element, such as an <a> for a link.
onClickfunction—Runs when the item is chosen with a click, Enter or Space.
disabledbooleanfalseDisables the item. It stays focusable, so people can still read it.
labelstring—Text for typeahead when the item's content is not plain text.
closeOnClickbooleantrueWhether choosing the item closes the menu.

These are the props of MenuItem. Menu takes Base UI's root props: open, onOpenChange, modal and disabled. MenuCheckboxItem takes checked, defaultChecked, onCheckedChange and closeOnClick (off by default). MenuRadioGroup takes value, defaultValue and onValueChange, and each MenuRadioItem a value; a MenuGroupLabel inside the group names it. Wrap a MenuSubTrigger and its MenuSubContent in a MenuSub. MenuTrigger takes render, usually <Button /> or <IconButton aria-label="…" />.

Styling hooks

Restyle it without forking: target the attributes, or set the tokens on a parent, a skin or the popup itself.

Attributes

data-popup-openon the trigger while the menu is open
data-highlightedon the item under the keyboard or pointer
data-checked · data-uncheckedon checkbox and radio items
data-disabledon a disabled item
data-tonedanger
data-sidetop · bottom (on the popup)

Tokens it reads

Color

--cml-accent-text--cml-border--cml-danger--cml-fg--cml-fg-muted--cml-fg-secondary--cml-focus-ring--cml-item-highlight-fg--cml-item-highlight-shadow--cml-popover-bg--cml-popover-border--cml-shadow-popover--cml-surface-raised

Shape & size

--cml-border-width--cml-font-size-field--cml-item-height--cml-item-padding--cml-popover-border-width--cml-popover-padding--cml-radius-control--cml-radius-item--cml-radius-popover--cml-toolbar-btn-size

Type & motion

--cml-duration-fast--cml-ease-standard--cml-font-body--cml-font-control--cml-font-field--cml-font-label--cml-font-weight-control--cml-motion-scale

This component only

--cml-corner-shape--cml-disabled-opacity--cml-item-check--cml-item-divider--cml-item-highlight--cml-item-hover--cml-menu-icons

Accessibility

Enter / Space / ↓On the trigger: opens the menu and focuses the first item.
↑On the trigger: opens the menu and focuses the last item.
↓ / ↑Moves between items, wrapping at the ends.
Home / EndJumps to the first or last item.
A–ZJumps to the next item that starts with that letter.
Enter / SpaceChooses the item; on a checkbox or radio item, toggles it and keeps the menu open.
→ / ←On a submenu trigger, → opens the submenu on its first item; inside it, ← closes it and goes back.
EscCloses the submenu, or the menu, and returns focus to its trigger.
TabCloses the menu and moves on.
Was this page helpful? · Edit this page on GitHub