Menubar
Keeps a row of menus on screen, like an editor's File, Edit and View.
Installation
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
└── MenubarRadioItemimport {
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
MenubarContent
| Prop | Type | Default |
|---|---|---|
align | "center" | "end" | "start" | "start" |
sideOffset | number | 3 |
alignOffset | number | 0 |
MenubarItem
| Prop | Type | Default |
|---|---|---|
inset | boolean | |
variant | "default" | "destructive" | "default" |
MenubarCheckboxItem
| Prop | Type | Default |
|---|---|---|
inset | boolean |
MenubarRadioItem
| Prop | Type | Default |
|---|---|---|
inset | boolean |
MenubarLabel
| Prop | Type | Default |
|---|---|---|
inset | boolean |
MenubarSubTrigger
| Prop | Type | Default |
|---|---|---|
inset | boolean |
MenubarSubContent
| Prop | Type | Default |
|---|---|---|
sideOffset | number | 4 |
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.
Menubarisslds-context-barwithslds-context-bar__secondary.MenubarTriggerisslds-context-bar__itemwith itsslds-context-bar__label-action.MenubarContentandMenubarSubContentareslds-dropdown.MenubarItem,MenubarCheckboxItemandMenubarRadioItemareslds-dropdown__item. Checked items show SLDS's selected check (slds-icon_selected) before the text.MenubarLabelisslds-dropdown__header, andMenubarSeparatorisslds-has-divider_top-space.MenubarSubTriggeris an item withslds-has-submenu.MenubarShortcutand 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.
| Prop | Value | SLDS | Notes |
|---|---|---|---|
MenubarItem variant | default | slds-dropdown__item | |
MenubarItem variant | destructive | none | SLDS has no destructive item. The text and icon take the error color; the highlight stays. |
MenubarItem inset | true | none | Starts 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
MenubarLabelinside aMenubarGrouporMenubarRadioGroup, 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.
Related
- Dropdown menuOpens a menu of actions or options from a button, like a record's row actions.
- Context menuOpens a menu of actions on right-click, like on a file tile or a list row.
- TabsSwitches between panels of related content.
- Button groupJoins related buttons into one control, like a record's Edit, Clone and More.