Menubar
A horizontal bar of menus, like the menu bar of a desktop application.
Anatomy
The menubar is a thin coordinator. It owns only a root element; the items it navigates are the triggers of the Menu
components rendered inside it.
<Menubar.Root>
<Menu.Root>
<Menu.Trigger />
<Portal>
<Menu.Positioner>
<Menu.Content>
<Menu.Item />
</Menu.Content>
</Menu.Positioner>
</Portal>
</Menu.Root>
</Menubar.Root>
Examples
Basic
Each Menu inside a Menubar.Root becomes one of its items. The menubar takes over roving tabindex, arrow key
navigation, Home/End, and typeahead across the triggers, and the menus coordinate opening and closing between
themselves. No extra prop or wrapper is needed.
Once one menu is open, moving to a sibling with the arrow keys or the pointer switches to it directly.
Nested Menus
Submenus work exactly as they do outside a menubar, with Menu.TriggerItem. ArrowRight on a submenu trigger opens the
submenu instead of moving to the next menu.
Vertical
Set orientation="vertical" to stack the triggers. Up and down then move between them, and ArrowRight opens the
focused menu as a fly-out.
Disabled
Set disabled on Menubar.Root to disable every trigger at once.
To disable a single menu instead, set disabled on its Menu.Trigger. It is skipped by keyboard navigation, never
becomes the tabbable item, and does not open on hover.
Root Provider
Use the useMenubar hook with Menubar.RootProvider to read the menubar's state from outside the component.
Guides
Portal the menus
Menu content must be rendered in a Portal. The menubar treats every element with role="menuitem" inside its root as
one of its own items, so a Menu.Positioner left inline would have its menu items picked up as menubar triggers and
keyboard navigation would land on them.
<Menu.Root>
<Menu.Trigger>File</Menu.Trigger>
{/* ✅ portalled out of the menubar root */}
<Portal>
<Menu.Positioner>
<Menu.Content>{/* ... */}</Menu.Content>
</Menu.Positioner>
</Portal>
</Menu.Root>
Skipping the animation between menus
Opening the first menu is a normal open and should animate. Moving from one menu to the next is a swap, and replaying the enter and exit animations on every step reads as flicker.
Both the outgoing and the incoming content carry data-instant for that swap, so styles can opt out of the animation
without giving it up for the first open:
[data-scope='menu'][data-part='content'][data-state='open'] {
animation: fade-in 150ms ease-out;
}
[data-scope='menu'][data-part='content'][data-state='closed'] {
animation: fade-out 100ms ease-in;
}
/* switching between menus in a menubar */
[data-scope='menu'][data-part='content'][data-instant] {
animation: none;
}
data-instant is set when the swap comes from the arrow keys or from hovering a sibling trigger. Closing a menu on its
own, by clicking its trigger again or pressing Escape, clears it, so the next open animates normally.
API Reference
Props
Root
Renders a <div> element.
| Prop | Default | Type |
|---|---|---|
asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. | |
disabled | false | booleanWhether the menubar (and all its menu triggers) is disabled. |
ids | Partial<{ root: string }>The ids of the elements in the menubar. Useful for composition. | |
loopFocus | true | booleanWhether to loop the keyboard navigation across the triggers. |
orientation | 'horizontal' | OrientationThe orientation of the menubar. |
render | ReactElement<unknown, string | JSXElementConstructor<any>> | RenderFn<EmptyState>Render the part as a custom element, combining their props and behavior. Pass an element to have the part's props merged into it, or a function to control the merge yourself and read the part's state. |
| Attribute | Description |
|---|---|
[data-menubar-root] | <uid> |
[data-orientation] | The orientation of the menubar |
[data-disabled] | Present when disabled |
[data-has-open-menu] | Present when a menu in the menubar is open |
RootProvider
Renders a <div> element.
| Prop | Default | Type |
|---|---|---|
value | UseMenubarReturn | |
asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. | |
render | ReactElement<unknown, string | JSXElementConstructor<any>> | RenderFn<EmptyState>Render the part as a custom element, combining their props and behavior. Pass an element to have the part's props merged into it, or a function to control the merge yourself and read the part's state. |
Context
API
| Property | Type |
|---|---|
hasOpenMenu | booleanWhether any menu within the menubar is open. |
orientation | OrientationThe orientation of the menubar. |
disabled | booleanWhether the menubar is disabled. |
getMenuContext | () => MenubarMenuContextReturns the config to pass to each top-level menu's `menubar` prop. Adapters usually expose this via a context so nested `<Menu>`s can read it. |
Accessibility
Complies with the Menubar WAI-ARIA design pattern.
Keyboard Support
| Key | Description |
|---|---|
ArrowRightArrowLeft | In a horizontal menubar, moves focus to the next/previous menu. If a menu is open, opens the sibling menu. |
ArrowDownArrowUp | In a vertical menubar, moves focus to the next/previous menu. In a horizontal menubar, opens the focused menu. |
EnterSpace | Opens the focused menu and highlights its first item. |
HomeEnd | Moves focus to the first/last menu. |
Esc | Closes the open menu and returns focus to its trigger. |