ComponentsNavigation

Menubar

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.

Radix Menubar components/menubar.tsx, lib/menu.tsxtheme · material · accent · density · font

Installation

$ pnpm add @vamos-ui/react

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.

LedgerlineFY 2026
Operating account€48,212.40Tax reserve€9,870.00

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.

Draft · saved 2 min ago

API

Menubar

PropTypeDefault
menus
Data-driven menus: { id, label, items: MenuEntry[], disabled?, permission? }. Rendered before children.
MenubarMenuEntry[]—
variant
bar is a hairline surface strip; ghost has no chrome (inside a Top bar or window header).
"bar" | "ghost""bar"
size
Minimum width and item size of every panel (180 / 220px). MenubarContent size overrides it per menu.
"sm" | "md""md"
value / defaultValue / onValueChange
The open menu (its MenubarMenu value). Empty string = closed.
string—
loop
Arrow keys wrap from the last menu to the first.
booleantrue
dir
Reading direction; ← → swap in RTL.
"ltr" | "rtl"—
aria-label
Name of the bar ("Document", "Invoices").
string—

MenubarMenu / MenubarTrigger

PropTypeDefault
value
MenubarMenu: id for a controlled bar.
string—
disabled
MenubarTrigger: greyed out and skipped by the arrow keys.
boolean—

MenubarContent / MenubarSubContent

PropTypeDefault
size
Panel width and item size.
"sm" | "md"bar size
align / sideOffset / alignOffset
Placement under the trigger. Collides with the viewport (12px padding).
…"start" / 6 / -4

MenubarItem

PropTypeDefault
onSelect
Click, Enter or Space; the menu closes. event.preventDefault() keeps it open.
(event) => void—
icon
Leading icon.
ReactNode—
shortcut
Keycap hint, e.g. "mod+shift+z" (⌘ on Mac, Ctrl elsewhere).
string | string[]—
description / badge
Second line / trailing count.
ReactNode—
tone
danger for destructive commands.
"default" | "danger""default"
inset
Reserve the indicator gutter so labels align with checkbox/radio items.
boolean—
disabled
Not selectable, skipped by the arrow keys.
boolean—

MenubarCheckboxItem / MenubarRadioGroup / MenubarRadioItem

PropTypeDefault
checked / onCheckedChange
CheckboxItem state (menuitemcheckbox).
boolean—
value / onValueChange
RadioGroup selection; each RadioItem has a value (menuitemradio).
string—
shortcut / description
As on MenubarItem.
…—

Other parts

PropTypeDefault
MenubarSub / MenubarSubTrigger
A submenu; opens on hover, Enter, Space or →.
…—
MenubarLabel / MenubarSeparator / MenubarGroup
Section heading (inset aligns it), divider, group.
…—
MenubarShortcut
Plain-text shortcut hint, when you don't want keycaps.
span—
MenubarEntries / MenubarMenus
Render MenuEntry[] inside your own MenubarContent, or MenubarMenuEntry[] inside your own Menubar.
{ items } / { menus }—