A dropdown of actions, wrapping the Base UI Menu. Full keyboard navigation, typeahead, checkbox and radio items, and submenus, on the same glass surface as the Select dropdown.

Playground

Open the menu and toggle the checkbox and radio items to see them stay open, then pick Reset to see a plain item close it; Compact shrinks every row at once.

Variants

Two sizes, set once on the root: default rows are 36px tall with 16px text, compact rows 28px with 14px text, and the trigger button takes its own matching size.

States

Open and highlighted are live (hover or arrow keys); checked and disabled are the ones you set, and keyboard focus stays on the popup while the highlight moves, so there is no per-item focus ring.

Submenus

Wrap a MenuSubmenuRoot around a MenuSubmenuTrigger and another MenuContent; it opens on hover or with the right arrow key, and the chevron renders automatically.

Styling states

Items carry data-highlighted under the cursor or arrow keys and data-checked on checkbox and radio items; the trigger carries data-popup-open while the menu is open:

.ub-menu-item[data-highlighted] {
  background: var(--ub-accent);
  color: var(--ub-accent-contrast);
}

Props

Everything Base UI's Menu parts accept passes through. The essentials:

PropTypeDefaultDescription
MenuRoot.size"default" | "compact""default"Sizes every item in the menu, submenus included.
MenuTrigger.renderReactElementThe real control that opens the menu, usually a Bones Button.
MenuContent.align"center" | "start" | "end"Alignment along the trigger; menus align start by default.
MenuContent.sidePositionerSideWhich side of the trigger to open on; below by default, beside for submenus.
MenuContent.sideOffsetnumber4Gap between the trigger and the menu, in pixels.
MenuItem.closeOnClickbooleantrueSet false to keep the menu open after the action runs.
MenuCheckboxItem.checkedbooleanControlled state (also defaultChecked, onCheckedChange).
MenuRadioGroup.valuestringSelected MenuRadioItem value (also defaultValue, onValueChange).

One quirk: plain items close the menu on click unless told otherwise, while checkbox and radio items stay open by default so the change is visible; pass closeOnClick on either to flip it.

Agent instructions

Working with a coding agent? Paste this into its context, or point it at llms.txt for the whole library.

MenuRoot, MenuTrigger, MenuContent, MenuItem, MenuCheckboxItem, MenuRadioGroup, MenuRadioItem, MenuGroup, MenuGroupLabel, MenuSeparator, MenuSubmenuRoot, MenuSubmenuTrigger, from @usebones/react.
- Structure: MenuRoot wraps MenuTrigger + MenuContent; items go inside the content. Attach the trigger to a real control via render={<Button ... />}.
- MenuItem runs onClick and closes (closeOnClick={false} keeps it open); disabled dims it and skips it. MenuCheckboxItem (defaultChecked/checked + onCheckedChange) and MenuRadioItem inside MenuRadioGroup (value + onValueChange) stay open; indicators render automatically.
- Group related items with MenuGroup + MenuGroupLabel; divide with MenuSeparator.
- Submenus: MenuSubmenuRoot wrapping MenuSubmenuTrigger + another MenuContent; the chevron is automatic.
- size on MenuRoot: "default" | "compact", flows to submenus; give the trigger Button the same size.
- Restyle in CSS via .ub-menu-popup, .ub-menu-item, [data-highlighted], [data-checked], [data-disabled], [data-popup-open] on the trigger, [data-starting-style]/[data-ending-style] for enter/exit. Tokens only.