Skip to main content

Overview

Menubar provides a horizontal menu bar with dropdown menus, similar to what you’d find in desktop applications. It supports submenus, keyboard navigation, and various item types including checkboxes and radio groups.

Features

  • Full keyboard navigation
  • Supports submenus with customizable alignments
  • Supports items, labels, groups of items
  • Supports checkable items (single or multiple)
  • Supports modal and non-modal modes
  • Customize side, alignment, offsets, collision handling
  • Focus automatically moved to first item when menu opens
  • Typeahead support
  • Dismissing and layering behavior highly customizable

Installation

npm install @radix-ui/react-menubar

Anatomy

import * as Menubar from '@radix-ui/react-menubar';

export default () => (
  <Menubar.Root>
    <Menubar.Menu>
      <Menubar.Trigger />
      <Menubar.Portal>
        <Menubar.Content>
          <Menubar.Label />
          <Menubar.Item />

          <Menubar.Group>
            <Menubar.Item />
          </Menubar.Group>

          <Menubar.CheckboxItem>
            <Menubar.ItemIndicator />
          </Menubar.CheckboxItem>

          <Menubar.RadioGroup>
            <Menubar.RadioItem>
              <Menubar.ItemIndicator />
            </Menubar.RadioItem>
          </Menubar.RadioGroup>

          <Menubar.Sub>
            <Menubar.SubTrigger />
            <Menubar.Portal>
              <Menubar.SubContent />
            </Menubar.Portal>
          </Menubar.Sub>

          <Menubar.Separator />
          <Menubar.Arrow />
        </Menubar.Content>
      </Menubar.Portal>
    </Menubar.Menu>
  </Menubar.Root>
);

API Reference

Root

Contains all the menu bar items.
value
string
The controlled value of the menu to open.
defaultValue
string
The value of the menu that should be open initially.
onValueChange
(value: string) => void
Event handler called when the value changes.
dir
'ltr' | 'rtl'
The reading direction. If omitted, assumes LTR.
loop
boolean
default:"true"
Whether keyboard navigation should loop from last item to first, and vice versa.
A top level menu item, contains a trigger with content combination.
value
string
A unique value that associates the item with a content.

Trigger

The button that toggles the menu content. By default, the menu opens on click.
asChild
boolean
default:"false"
Change the default rendered element for the one passed as a child.

Portal

When used, portals the content part into the body.
container
HTMLElement
Specify a container element to portal the content into.
forceMount
boolean
Used to force mounting when more control is needed.

Content

The component that pops out when a menu is open.
loop
boolean
default:"false"
Whether keyboard navigation should loop from last item to first, and vice versa.
onCloseAutoFocus
(event: Event) => void
Event handler called when focus moves back after closing.
onEscapeKeyDown
(event: KeyboardEvent) => void
Event handler called when the escape key is down.
onPointerDownOutside
(event: PointerDownOutsideEvent) => void
Event handler called when a pointer event occurs outside the bounds of the component.
onFocusOutside
(event: FocusOutsideEvent) => void
Event handler called when focus moves outside the bounds of the component.
onInteractOutside
(event: InteractOutsideEvent) => void
Event handler called when an interaction happens outside the bounds of the component.
forceMount
boolean
Used to force mounting when more control is needed.
side
'top' | 'right' | 'bottom' | 'left'
default:"'bottom'"
The preferred side of the trigger to render against.
sideOffset
number
default:"0"
The distance in pixels from the trigger.
align
'start' | 'center' | 'end'
default:"'center'"
The preferred alignment against the trigger.
alignOffset
number
default:"0"
An offset in pixels from the “start” or “end” alignment options.
avoidCollisions
boolean
default:"true"
When true, overrides the side and align preferences to prevent collisions with boundary edges.
collisionBoundary
Element | Element[]
default:"[]"
The element(s) used as collision boundary.
collisionPadding
number | Partial<Record<Side, number>>
default:"0"
The distance in pixels from the boundary edges where collision detection should occur.
arrowPadding
number
default:"0"
The padding between the arrow and the edges of the content.
sticky
'partial' | 'always'
default:"'partial'"
The sticky behavior on the align axis.
hideWhenDetached
boolean
default:"false"
Whether to hide the content when the trigger becomes fully occluded.

Item

The component that contains the menu items.
disabled
boolean
When true, prevents the user from interacting with the item.
onSelect
(event: Event) => void
Event handler called when the user selects an item.
textValue
string
Optional text used for typeahead purposes. By default the typeahead behavior will use the text content.

CheckboxItem

An item that can be controlled and rendered like a checkbox.
checked
boolean | 'indeterminate'
The controlled checked state of the item.
onCheckedChange
(checked: boolean) => void
Event handler called when the checked state changes.
disabled
boolean
When true, prevents the user from interacting with the item.

RadioGroup

Used to group multiple RadioItems.
value
string
The controlled value of the radio item to check.
onValueChange
(value: string) => void
Event handler called when the value changes.

RadioItem

An item that can be controlled and rendered like a radio.
value
string
required
The unique value of the item.
disabled
boolean
When true, prevents the user from interacting with the item.

ItemIndicator

Renders when the parent CheckboxItem or RadioItem is checked. You can style this element directly, or use it as a wrapper to put an icon into.
forceMount
boolean
Used to force mounting when more control is needed.

Separator

Used to visually separate items in the menu.

Sub

Contains all the parts of a submenu.
defaultOpen
boolean
The open state of the submenu when it is initially rendered.
open
boolean
The controlled open state of the submenu.
onOpenChange
(open: boolean) => void
Event handler called when the open state changes.

SubTrigger

An item that opens a submenu.
disabled
boolean
When true, prevents the user from interacting with the item.
textValue
string
Optional text used for typeahead purposes.

SubContent

The component that pops out when a submenu is open.
Accepts all the same props as Content.

Group

Used to group multiple items. Use in conjunction with Label to ensure good accessibility via automatic labelling.

Label

Used to render a label. It won’t be focusable using arrow keys.

Arrow

An optional arrow element to render alongside the content.
width
number
default:"10"
The width of the arrow in pixels.
height
number
default:"5"
The height of the arrow in pixels.

Example

import * as Menubar from '@radix-ui/react-menubar';
import { CheckIcon } from '@radix-ui/react-icons';
import './styles.css';

export default () => {
  const [checkedSelection, setCheckedSelection] = React.useState(['1']);
  const [person, setPerson] = React.useState('pedro');

  return (
    <Menubar.Root className="MenubarRoot">
      <Menubar.Menu>
        <Menubar.Trigger className="MenubarTrigger">File</Menubar.Trigger>
        <Menubar.Portal>
          <Menubar.Content className="MenubarContent" sideOffset={5} align="start">
            <Menubar.Item className="MenubarItem">New Tab</Menubar.Item>
            <Menubar.Item className="MenubarItem">New Window</Menubar.Item>
            <Menubar.Separator className="MenubarSeparator" />
            <Menubar.Item className="MenubarItem">Share</Menubar.Item>
            <Menubar.Separator className="MenubarSeparator" />
            <Menubar.Item className="MenubarItem">Print</Menubar.Item>
          </Menubar.Content>
        </Menubar.Portal>
      </Menubar.Menu>

      <Menubar.Menu>
        <Menubar.Trigger className="MenubarTrigger">Edit</Menubar.Trigger>
        <Menubar.Portal>
          <Menubar.Content className="MenubarContent" sideOffset={5} align="start">
            <Menubar.Item className="MenubarItem">Undo</Menubar.Item>
            <Menubar.Item className="MenubarItem">Redo</Menubar.Item>
            <Menubar.Separator className="MenubarSeparator" />
            <Menubar.Item className="MenubarItem">Cut</Menubar.Item>
            <Menubar.Item className="MenubarItem">Copy</Menubar.Item>
            <Menubar.Item className="MenubarItem">Paste</Menubar.Item>
          </Menubar.Content>
        </Menubar.Portal>
      </Menubar.Menu>

      <Menubar.Menu>
        <Menubar.Trigger className="MenubarTrigger">View</Menubar.Trigger>
        <Menubar.Portal>
          <Menubar.Content className="MenubarContent" sideOffset={5} align="start">
            <Menubar.CheckboxItem
              className="MenubarCheckboxItem"
              checked={checkedSelection.includes('1')}
              onCheckedChange={(checked) =>
                setCheckedSelection((prev) =>
                  checked ? [...prev, '1'] : prev.filter((c) => c !== '1')
                )
              }
            >
              <Menubar.ItemIndicator className="MenubarItemIndicator">
                <CheckIcon />
              </Menubar.ItemIndicator>
              Show Bookmarks Bar
            </Menubar.CheckboxItem>
            <Menubar.CheckboxItem
              className="MenubarCheckboxItem"
              checked={checkedSelection.includes('2')}
              onCheckedChange={(checked) =>
                setCheckedSelection((prev) =>
                  checked ? [...prev, '2'] : prev.filter((c) => c !== '2')
                )
              }
            >
              <Menubar.ItemIndicator className="MenubarItemIndicator">
                <CheckIcon />
              </Menubar.ItemIndicator>
              Show Full URLs
            </Menubar.CheckboxItem>
            <Menubar.Separator className="MenubarSeparator" />
            <Menubar.Item className="MenubarItem" disabled>
              Reload
            </Menubar.Item>
          </Menubar.Content>
        </Menubar.Portal>
      </Menubar.Menu>
    </Menubar.Root>
  );
};

Accessibility

Adheres to the Menu Button WAI-ARIA design pattern and uses roving tabindex to manage focus movement among menu items.

Keyboard Interactions

  • Space/Enter - Opens the menu and focuses the first item.
  • ArrowDown - Opens the menu and focuses the first item.
  • ArrowUp - Opens the menu and focuses the last item.
  • ArrowRight/ArrowLeft - When focus is on a trigger, moves focus to the next or previous trigger.
  • Esc - Closes the menu and moves focus to the trigger.

Build docs developers (and LLMs) love