Skip to content

Menubar

Keeps a row of menus on screen, like an editor's File, Edit and View.

Library
What’s this?

Installation

pnpm dlx shadcn@latest add @wisty/menubar

The CLI installs the Radix or Base UI file to match your project, with what it builds on: dropdown-menu.

If your project doesn't have Wisty UI's theme yet, add it once with npx shadcn@latest add @wisty/cosmos. Until then, components keep shadcn's default look. Installation has the details.

When to use

Use it

  • An app or editor needs a row of menus that stays on screen, like File, Edit and View.
  • A record or workspace has many commands, and grouping them under a few menus keeps the page calm.
  • People expect desktop-style keyboard use: arrow keys along the bar and through each menu.

Don't use it

  • One button opens a few actions. Use Dropdown menu.
  • The links move between pages or sections of an app. Use links or Tabs.
  • People right-click on an element to act on it. Use Context menu.
  • There are only two or three commands with room for them. Show buttons, or a Button group.

Usage

Menubar
└── MenubarMenu
    ├── MenubarTrigger
    └── MenubarContent
        ├── MenubarItem
        │   └── MenubarShortcut
        ├── MenubarSub
        │   ├── MenubarSubTrigger
        │   └── MenubarSubContent
        │       └── MenubarItem
        ├── MenubarSeparator
        └── MenubarGroup
            ├── MenubarLabel
            ├── MenubarCheckboxItem
            └── MenubarRadioGroup
                └── MenubarRadioItem
import {
  Menubar,
  MenubarContent,
  MenubarItem,
  MenubarMenu,
  MenubarTrigger,
} from "@/components/ui/menubar"
<Menubar aria-label="Flow builder">
  <MenubarMenu>
    <MenubarTrigger>Flow</MenubarTrigger>
    <MenubarContent>
      <MenubarItem>Save</MenubarItem>
    </MenubarContent>
  </MenubarMenu>
</Menubar>

Run an item's action with onClick on MenubarItem; onSelect exists only in Radix projects. inset on an item, label or submenu trigger starts its text where a checked item's text starts, so it lines up under checkbox and radio items. The menus aren't modal, so the page stays scrollable and clickable while one is open. In Base UI projects modal on Menubar changes that; in Radix projects the menubar is never modal.

In Radix projects, checking a checkbox or radio item closes the menu; call event.preventDefault() in its onSelect to keep it open. In Base UI projects the menu stays open; pass closeOnClick to close it.

Examples

Checkbox and radio items

A View menu of `MenubarCheckboxItem`s and `MenubarRadioItem`s under `MenubarLabel`s, and an `inset` item lined up with them.

Submenu

Account's Share item, a `MenubarSubTrigger`, opens a `MenubarSubContent` of Email, Chatter post and Copy link.

API reference

SLDS mapping

SLDS has no menubar. Menubar takes the item look of Global Navigation's context bar, without its app name or primary area, and its menus are SLDS menus styled as in Dropdown menu.

  • Menubar is slds-context-bar with slds-context-bar__secondary.
  • MenubarTrigger is slds-context-bar__item with its slds-context-bar__label-action.
  • MenubarContent and MenubarSubContent are slds-dropdown.
  • MenubarItem, MenubarCheckboxItem and MenubarRadioItem are slds-dropdown__item. Checked items show SLDS's selected check (slds-icon_selected) before the text.
  • MenubarLabel is slds-dropdown__header, and MenubarSeparator is slds-has-divider_top-space.
  • MenubarSubTrigger is an item with slds-has-submenu. MenubarShortcut and a disabled trigger have no SLDS counterpart.

Known gaps:

  • No current-page state (slds-is-active). Menubar holds commands, not navigation.
  • No nubbin, and no slds-dropdown_length-* heights. A menu scrolls only when it runs out of room on screen.
  • Icons are lucide's, not SLDS's utility icons.
PropValueSLDSNotes
MenubarItem variantdefaultslds-dropdown__item
MenubarItem variantdestructivenoneSLDS has no destructive item. The text and icon take the error color; the highlight stays.
MenubarItem insettruenoneStarts the text where a checked item's text starts.

Keyboard interactions

Keys Action
Right Arrow, Left Arrow On a trigger, moves focus to the next or previous trigger.
Enter, Space or Down Arrow On a trigger, opens its menu and focuses the first item.
Down Arrow, Up Arrow In a menu, moves focus to the next or previous item.
Right Arrow, Left Arrow In a menu, closes it and opens the next or previous trigger's menu.
Right Arrow On a submenu trigger, opens the submenu and focuses its first item.
Left Arrow In a submenu, closes it and returns focus to its trigger.
Enter or Space Runs the focused item, or checks it.
Escape Closes the menu and returns focus to its trigger.

Only one trigger is in the tab order at a time, so Tab leaves the bar. In Radix projects the arrow keys skip disabled items and triggers. In Base UI projects focus lands on them, but Enter and Space don't run them.

Accessibility

  • Give the bar a name with aria-label, like "Report builder", so screen readers can tell it from another bar on the page.
  • A disabled item still reads out. Say why it's unavailable in nearby text if it matters.

Motion

  • In Lightning Blue, the trigger's hover fill fades in over 0.25s. Cosmos has no hover fill, so nothing fades there.
  • The fade only changes color, so it runs with reduced motion too.

Responsive behavior

  • The bar fills its container's width and doesn't wrap or scroll. Pass className="w-fit" to size it to its triggers.
  • Triggers don't shrink. A long label ends in an ellipsis at a width that differs per theme, so keep labels to one or two words.

Rules

  • Put each MenubarLabel inside a MenubarGroup or MenubarRadioGroup, or the menu can throw.
  • A trigger's label is plain text. Don't put a Button or an icon-only control in it.
  • Use variant="destructive" only for actions that delete or can't be undone, and put them last, after a separator.
  • Don't restyle trigger hover, focus or open colors. They come from the theme tokens.
  • Don't use a menubar for page navigation. It has no current-page state.