When to Use
Use Menubar for desktop-like application commands grouped under headings such
as File, Edit, and View. Use Menu for one standalone command menu,
NavigationMenu for website navigation, and NavList for a normal list of links.
Menubar is usually unnecessary for a small set of buttons.
Features
The behavior Atom owns before your product adds appearance.
- Renders a
role="menubar" root with roving top-level trigger focus.
- Supports horizontal and vertical orientation.
- Opens adjacent top-level menus with ArrowLeft and ArrowRight.
- Mirrors horizontal top-level navigation in RTL through
dir or Direction.Provider.
- Provides menu items, checkbox items, radio items, groups, separators, and submenus through the
Menubar namespace.
- Supports controlled and uncontrolled active top-level menu state.
- Preserves Root and Content behavior through
asChild and render
composition.
- Supports per-menu
closeOnSelect, looping, and Escape close behavior.
- Exposes state and styling data attributes without shipping styles.
Import
Anatomy
API Reference
Menubar top-level coordination is implemented by Menubar.Root, Menubar.Menu,
Menubar.Trigger, and Menubar.Content. The item, group, separator, and
submenu parts share the same behavior as Menu, but are exposed directly on the
Menubar namespace so consumers can build a complete menubar without importing
Menu.
All DOM-rendering parts also accept their underlying native DOM props except
for props Atom owns, such as managed roles and children.
Root
Contains the top-level menus and manages the active top-level menu value.
Renders a div with role="menubar" and the resolved dir attribute.
children | ReactNode | required |
asChild | boolean | false |
render | RenderProp | - |
value | string | null | - |
defaultValue | string | - |
onValueChange | (value: string | null) => void | - |
loop | boolean | true |
dir | "ltr" | "rtl" | Direction.Provider |
orientation | "horizontal" | "vertical" | "horizontal" |
className | string | - |
aria-orientation | Root orientation |
[data-slot] | "menubar" by default |
[data-orientation] | "horizontal" | "vertical" |
Provides one top-level menu scope. Each Menu value must be unique within the
same Root.
children | ReactNode | required |
value | string | required |
closeOnSelect | boolean | true |
loop | boolean | true |
closeOnEscape | boolean | true |
closeOnSelect is the default selection behavior for normal menu items inside
that top-level menu. Checkbox and radio items default to staying open unless
their own closeOnSelect prop is set.
Trigger
Opens and closes one top-level menu. Trigger renders a native button with
role="menuitem" so it is a valid child of the menubar root. It uses roving
tabIndex so only the active top-level trigger is tabbable.
children | ReactNode | required |
disabled | boolean | false |
asChild | boolean | false |
render | RenderProp | - |
className | string | - |
aria-haspopup | "menu" |
aria-expanded | true | false |
aria-controls | Associated menu content id |
[data-slot] | "menubar-trigger" by default |
[data-state] | "open" | "closed" |
[data-disabled] | Present when disabled |
Content
Renders the positioned top-level menu surface for a Menu as a portalled div
with role="menu" and tabIndex={-1}.
children | ReactNode | required |
asChild | boolean | false |
render | RenderProp | - |
side | "top" | "right" | "bottom" | "left" | "bottom" |
align | "start" | "center" | "end" | "start" |
sideOffset | number | 4 |
loop | boolean | menu value |
ariaLabel | string | - |
className | string | - |
aria-orientation | "vertical" |
aria-label | From ariaLabel |
aria-labelledby | Trigger id when ariaLabel is not provided |
[data-slot] | "menu-content" by default |
[data-state] | "open" | "closed" |
[data-side] | Resolved side |
[data-align] | Resolved align |
[data-positioned] | Present after positioning is ready |
Item
Renders an actionable menu item with role="menuitem" and tabIndex={-1}.
children | ReactNode | required |
value | string | required |
textValue | string | children text or value |
onSelect | () => void | - |
disabled | boolean | false |
closeOnSelect | boolean | menu value |
asChild | boolean | false |
render | RenderProp | - |
className | string | - |
aria-disabled | Present when disabled |
[data-slot] | "menu-item" by default |
[data-highlighted] | Present when highlighted |
[data-disabled] | Present when disabled |
[data-value] | Item value |
CheckboxItem
Renders a menuitemcheckbox with tabIndex={-1}.
children | ReactNode | required |
value | string | required |
textValue | string | children text or value |
checked | boolean | "indeterminate" | false |
onCheckedChange | (checked: boolean) => void | - |
disabled | boolean | false |
closeOnSelect | boolean | false |
className | string | - |
aria-checked | true | false |
aria-disabled | Present when disabled |
[data-slot] | "menu-checkbox-item" by default |
[data-highlighted] | Present when highlighted |
[data-disabled] | Present when disabled |
[data-checked] | Present when checked |
[data-value] | Item value |
RadioGroup
Provides radio selection state for RadioItem. Renders a div with
role="group".
children | ReactNode | required |
value | string | - |
onValueChange | (value: string) => void | - |
className | string | - |
[data-slot] | "menu-radio-group" by default |
Radio item values are scoped to their parent radio group for highlighting and
keyboard movement, so separate groups can reuse values such as "default"
inside the same menubar menu.
RadioItem
Renders a menuitemradio with tabIndex={-1}.
children | ReactNode | required |
value | string | required |
textValue | string | children text or value |
disabled | boolean | false |
closeOnSelect | boolean | false |
className | string | - |
aria-checked | true | false |
aria-disabled | Present when disabled |
[data-slot] | "menu-radio-item" by default |
[data-highlighted] | Present when highlighted |
[data-disabled] | Present when disabled |
[data-checked] | Present when checked |
[data-value] | Public radio value |
Group
Groups related menu items. Renders a div with role="group".
children | ReactNode | required |
className | string | - |
[data-slot] | "menu-group" by default |
Separator
Renders a decorative separator with role="separator".
aria-orientation | "horizontal" |
[data-slot] | "menu-separator" by default |
Sub
Provides nested submenu state.
children | ReactNode | required |
open | boolean | - |
defaultOpen | boolean | false |
onOpenChange | (open: boolean) => void | - |
SubTrigger
Renders the item that opens a nested submenu with role="menuitem" and
tabIndex={-1}. Mouse hover opening starts only after the pointer actually
moves over the item, so newly positioned content beneath a stationary pointer
does not open it.
children | ReactNode | required |
value | string | required |
textValue | string | children text or value |
disabled | boolean | false |
className | string | - |
aria-haspopup | "menu" |
aria-expanded | true | false |
aria-disabled | Present when disabled |
[data-slot] | "menu-sub-trigger" by default |
[data-state] | "open" | "closed" |
[data-highlighted] | Present when highlighted |
[data-disabled] | Present when disabled |
[data-value] | Trigger value |
SubContent
Renders the positioned nested submenu surface as a portalled div with
role="menu" and tabIndex={-1}.
children | ReactNode | required |
sideOffset | number | 4 |
loop | boolean | true |
ariaLabel | string | - |
className | string | - |
aria-orientation | "vertical" |
aria-label | From ariaLabel |
aria-labelledby | SubTrigger id when ariaLabel is not provided |
[data-menu-sub-content] | Present |
[data-slot] | "menu-sub-content" by default |
[data-state] | "open" | "closed" |
[data-side] | Resolved side |
[data-positioned] | Present after positioning is ready |
Advanced top-level parts can use useMenubarContext and
useMenubarMenuContext; the matching providers and context value types are
also public exports. Shared item parts use the Menu contexts documented above.
Examples
Portal, Arrow, Label, and ItemIndicator use the shared Menu contract.
CheckboxItem supports mixed state and all retained DOM parts accept refs,
native props, asChild, and render. Hover switching is mouse-only; touch and
pen use click/tap.
Accessibility
Follows the WAI-ARIA menubar pattern.
Top-level triggers use roving focus and
open menus with keyboard or pointer input. Top-level triggers expose
role="menuitem" so the role="menubar" root has valid menuitem children.
Horizontal ArrowLeft and ArrowRight navigation and nested submenu placement
mirror in RTL when dir="rtl" is set on Menubar.Root or inherited from
Direction.Provider. When an open menubar moves between top-level triggers,
focus remains owned by the active trigger so Enter, Space, and Escape
target the active menu.
Pointer/tap-opened menus focus the first item; ArrowDown and ArrowUp seed the
first and last item for keyboard opening. Portalled menu
content registers with a parent modal focus scope when opened inside Dialog,
Drawer, or another modal primitive. Menubar menu content inherits Menu
typeahead behavior for printable-character searches.
ArrowRight / ArrowLeft | Moves horizontal top-level focus, mirrored in RTL |
ArrowDown / ArrowUp | Moves vertical top-level focus; in horizontal mode opens first/last item |
Home / End | Moves to the first or last top-level trigger, or item inside open content |
Enter / Space on trigger | Opens or closes the top-level menu |
Enter / Space on item | Selects the focused item unless disabled |
Escape | Closes the topmost submenu first, then the active top-level menu |
| Printable character | Typeahead search inside open menu content |
Tab / Shift+Tab | Closes and exits after/before the complete Menubar Root |
Changelog
Unreleased
0.24.0
- Added public Agent Knowledge for component selection, required composition,
recurring mistakes, and validation.
0.20.6
- Inherited movement-gated submenu hover intent so opening a top-level menu
cannot also open a submenu that appears beneath a stationary pointer.
0.12.1
- Fixed Root and Content to preserve their behavior, refs, native props, and
children through the documented
asChild and render composition paths.
- Fixed Content composition to preserve consumer
onKeyDownCapture handlers
before Menubar-owned adjacent-menu navigation.
0.12.0
- Added horizontal/vertical orientation with matching ARIA/data state and
orientation-aware top-level roving focus.
- Added Trigger ref,
asChild, and render composition and made hover
switching mouse-only while keeping click/tap universal.
- Inherited real menu-item focus, complete shared anatomy, mixed state,
geometry variables, submenu corrections, and whole-Menubar Tab exit.
0.3.1
- Inherited reliable Menu exit-presence cleanup for closed Menubar and submenu
Content under global motion CSS.
0.2.0
- Fixed local
Menubar.Root dir="rtl" so shared nested submenu placement also
mirrors to the left, matching Direction.Provider dir="rtl".
- Fixed adjacent top-level menu handoff so the active trigger keeps focus for
Enter, Space, and Escape after ArrowLeft or ArrowRight navigation.
- Fixed custom
data-slot overrides on Menubar.Root and Menubar.Trigger.
- Added
Direction.Provider and dir support to mirror Menubar top-level
ArrowLeft and ArrowRight navigation in RTL.
- Inherited the shared Menu typeahead behavior so a single-character search
cycles from the current matching item while multi-character buffers still
match exact prefixes.
- Fixed pointer-open behavior so clicking or hovering between top-level menus
opens content without pre-highlighting the first item; keyboard ArrowDown and
ArrowUp still seed first and last item highlight.
- Registered shared Menu content with parent modal focus scopes so Menubar
menus can remain valid focus targets inside Dialog, Drawer, and other modal
primitives.
- Fixed
Menubar.Trigger semantics so top-level triggers expose role="menuitem"
as valid children of the role="menubar" root.
- Inherited the shared Menu radio item fix so separate Menubar radio groups can
reuse the same public values without sharing highlight state.
- Inherited the shared Menu highlight fix so pointer movement over non-item
content or item gaps does not reset highlight back to the first item.
- Added shared menu item parts to the
Menubar namespace object.
- Refined
Menubar.Content keyboard handler dependencies to avoid recreating callbacks from the full context objects.
0.1.0