Menubar

A horizontal bar of menus, like the menu bar of a desktop application.

Loading...

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.

PropDefaultType
asChild
boolean

Use the provided child element as the default rendered element, combining their props and behavior.

For more details, read our Composition guide.
disabledfalse
boolean

Whether the menubar (and all its menu triggers) is disabled.

ids
Partial<{ root: string }>

The ids of the elements in the menubar. Useful for composition.

loopFocustrue
boolean

Whether to loop the keyboard navigation across the triggers.

orientation'horizontal'
Orientation

The 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.

AttributeDescription
[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.

PropDefaultType
value
UseMenubarReturn

asChild
boolean

Use 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

PropertyType
hasOpenMenu
boolean

Whether any menu within the menubar is open.

orientation
Orientation

The orientation of the menubar.

disabled
boolean

Whether the menubar is disabled.

getMenuContext
() => MenubarMenuContext

Returns 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

KeyDescription
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.