1. Home
  2. ChevronRightUi
  3. ChevronRightMenu

Menu

Composable dropdown and nesting context menus.

The Menu primitive is a modular navigation and option selector dropdown component that supports keyboard accessibility, nested sub-menus, search indexing, and selection checkboxes.

It's a thin wrapper around react-aria-components Menu, so you keep Roving Tabindex, type-ahead, item roles, and selection-mode handling for free. Boltdocs handles the spacing and focus ring.

Reach for Menu when you need: a kebab "..." trigger with actions, a "Sort by" filter dropdown, a "Switch version" picker, or any list of mutually exclusive options. Prefer Popover for free-form content (forms, rich widgets) — menus are for actions.


ImportLink

import { Menu } from 'boltdocs/primitives'

Quick StartLink

Compose a fully accessible actions dropdown menu:

import { Menu, Button } from 'boltdocs/primitives'

export default function FileActions() {
  return (
    <Menu.Trigger placement="bottom start">
      <Button className="px-4 py-2 bg-primary-500 text-white rounded-lg">
        Actions
      </Button>
      <Menu className="p-1 bg-surface border border-subtle rounded-lg shadow-lg w-48 flex flex-col gap-0.5">
        <Menu.Item
          onAction={() => alert('New document created!')}
          className="px-3 py-1.5 text-xs text-body hover:bg-soft rounded cursor-default"
        >
          New File
        </Menu.Item>
        <Menu.Item
          onAction={() => alert('Document copied!')}
          className="px-3 py-1.5 text-xs text-body hover:bg-soft rounded cursor-default"
        >
          Duplicate File
        </Menu.Item>
        <Menu.Separator className="border-t border-subtle my-1" />
        <Menu.Item
          onAction={() => alert('Document deleted!')}
          className="px-3 py-1.5 text-xs text-danger-500 hover:bg-danger-500/10 rounded cursor-default"
        >
          Delete File
        </Menu.Item>
      </Menu>
    </Menu.Trigger>
  )
}

Composable Sub-ComponentsLink

Compose rich selection menus and nested layout trees using the following namespaces:

ComponentHTML TagDescriptionProps
Menu.Root / Menu<div> (menu)Wrapper containing the menu items list viewport.MenuProps
Menu.TriggerWrapperWraps the trigger Button and the Menu overlay popup.MenuTriggerProps
Menu.SubTriggerWrapperWraps parent trigger items and nested child submenu layers.SubmenuTriggerProps
Menu.Item<div> (menuitem)A single clickable item inside the menu selection list.MenuItemProps
Menu.Section<div>Groups a collection of items under a specific section label.MenuSectionProps
Menu.Separator<hr>Visual separator dividing option categories.SeparatorProps

Component PropsLink

Inherits standard React Aria MenuProps settings:

PropertyTypeDefaultDescription
onAction(key: Key) => voidundefinedCallback invoked when any non-disabled item is clicked/selected.
classNamestringundefinedCustom CSS classes.

Inherits React Aria MenuTriggerProps plus:

PropertyTypeDefaultDescription
placement'bottom' | 'top' | 'left' | 'right' | 'start' | 'end''bottom'Alignment position relative to trigger.

Inherits standard React Aria MenuItemProps (e.g. isDisabled, onAction):

PropertyTypeDefaultDescription
textValuestringundefinedText equivalent value matching the item for auto-suggest type-ahead.
PropertyTypeDefaultDescription
titlestringundefinedSection label heading text.

PitfallsLink

  • Menu is for actions, not navigation. If clicking an item navigates somewhere, it's clearer to use a Listbox or a column of NavLinks. Menus imply "select and stay on the page" semantics.
  • <Menu.Item onAction> versus onPress. onAction is fired on selection (Enter / click); onPress fires on press start. Use onAction for committing the choice; use onPress for transient feedback like hover-previewing.
  • Sections need an aria-label-equivalent. When you use Menu.Section, set its title so screen readers announce the section change.
Last updated on July 27, 2026

Was this page helpful?