A desktop-app menu bar — File, Edit, View — for editors, back-office tools and anything that runs like an application. One tab stop, arrow keys between menus, submenus, checkbox and radio items, keycap shortcuts. Same item parts and MenuEntry model as Dropdown Menu and Context Menu.
Installation
The whole kit as one package — get updates by bumping the version. Add the styles to globals.css: @import "@vamos-ui/react/styles.css";
Usage
import { Menubar, MenubarMenu, MenubarTrigger, MenubarContent, MenubarItem } from "@vamos-ui/react";
<Menubar aria-label="Document">
<MenubarMenu>
<MenubarTrigger>File</MenubarTrigger>
<MenubarContent>
<MenubarItem shortcut="mod+s" onSelect={save}>Save</MenubarItem>
</MenubarContent>
</MenubarMenu>
</Menubar>
// or from data
<Menubar aria-label="Invoices" menus={[{ id: "file", label: "File", items: entries }]} />Keyboard: Tab reaches the bar once; ← → move between triggers (and keep a menu open while moving); ↓, Enter or Space open; Esc closes and returns focus; typing jumps to an item.
For a single menu behind a button use Dropdown Menu; for site navigation use Navigation Menu. A menubar is for commands.
Panels portal into the nearest ThemeScope. Only the first layer is glass; submenus are opaque.
Examples
From data (billing)
menus takes the shared MenuEntry model: items, submenus, checkbox and radio entries, separators. A menu with a failing permission is hidden.
Showing all invoices, grouped by client. The Admin menu appears only when can("billing.admin") is true.
Inside a window header
variant="ghost" drops the strip; size="sm" narrows every panel. A disabled trigger is skipped by the arrow keys.
Post editor toolbar (CMS)
Menus on the start side, status and the one primary action on the end. Shortcuts are display only — bind them with useHotkeys.
API
Menubar
| Prop | Type | Default |
|---|---|---|
menusData-driven menus: { id, label, items: MenuEntry[], disabled?, permission? }. Rendered before children. | MenubarMenuEntry[] | — |
variantbar is a hairline surface strip; ghost has no chrome (inside a Top bar or window header). | "bar" | "ghost" | "bar" |
sizeMinimum width and item size of every panel (180 / 220px). MenubarContent size overrides it per menu. | "sm" | "md" | "md" |
value / defaultValue / onValueChangeThe open menu (its MenubarMenu value). Empty string = closed. | string | — |
loopArrow keys wrap from the last menu to the first. | boolean | true |
dirReading direction; ← → swap in RTL. | "ltr" | "rtl" | — |
aria-labelName of the bar ("Document", "Invoices"). | string | — |
MenubarMenu / MenubarTrigger
| Prop | Type | Default |
|---|---|---|
valueMenubarMenu: id for a controlled bar. | string | — |
disabledMenubarTrigger: greyed out and skipped by the arrow keys. | boolean | — |
MenubarContent / MenubarSubContent
| Prop | Type | Default |
|---|---|---|
sizePanel width and item size. | "sm" | "md" | bar size |
align / sideOffset / alignOffsetPlacement under the trigger. Collides with the viewport (12px padding). | … | "start" / 6 / -4 |
MenubarItem
| Prop | Type | Default |
|---|---|---|
onSelectClick, Enter or Space; the menu closes. event.preventDefault() keeps it open. | (event) => void | — |
iconLeading icon. | ReactNode | — |
shortcutKeycap hint, e.g. "mod+shift+z" (⌘ on Mac, Ctrl elsewhere). | string | string[] | — |
description / badgeSecond line / trailing count. | ReactNode | — |
tonedanger for destructive commands. | "default" | "danger" | "default" |
insetReserve the indicator gutter so labels align with checkbox/radio items. | boolean | — |
disabledNot selectable, skipped by the arrow keys. | boolean | — |
MenubarCheckboxItem / MenubarRadioGroup / MenubarRadioItem
| Prop | Type | Default |
|---|---|---|
checked / onCheckedChangeCheckboxItem state (menuitemcheckbox). | boolean | — |
value / onValueChangeRadioGroup selection; each RadioItem has a value (menuitemradio). | string | — |
shortcut / descriptionAs on MenubarItem. | … | — |
Other parts
| Prop | Type | Default |
|---|---|---|
MenubarSub / MenubarSubTriggerA submenu; opens on hover, Enter, Space or →. | … | — |
MenubarLabel / MenubarSeparator / MenubarGroupSection heading (inset aligns it), divider, group. | … | — |
MenubarShortcutPlain-text shortcut hint, when you don't want keycaps. | span | — |
MenubarEntries / MenubarMenusRender MenuEntry[] inside your own MenubarContent, or MenubarMenuEntry[] inside your own Menubar. | { items } / { menus } | — |