Menubar
A desktop-app style horizontal menu bar (File / Edit / View / Help) with shared open state, hover-switch behaviour, and arrow-key navigation between top-level triggers.
Playground
Installation
pnpm add @tessinaui/uiUsage
import {
Menubar,
MenubarMenu,
MenubarTrigger,
MenubarContent,
MenubarItem,
MenubarSeparator,
MenubarCheckboxItem,
MenubarRadioGroup,
MenubarRadioItem,
MenubarSub,
MenubarSubTrigger,
MenubarSubContent,
MenubarLabel,
MenubarShortcut,
} from "@tessinaui/ui";<Menubar>
<MenubarMenu value="file">
<MenubarTrigger>File</MenubarTrigger>
<MenubarContent>
<MenubarItem shortcut="⌘N">New tab</MenubarItem>
<MenubarItem shortcut="⌘⇧N">New window</MenubarItem>
<MenubarSeparator />
<MenubarItem shortcut="⌘P">Print…</MenubarItem>
</MenubarContent>
</MenubarMenu>
<MenubarMenu value="edit">
<MenubarTrigger>Edit</MenubarTrigger>
<MenubarContent>
<MenubarItem shortcut="⌘Z">Undo</MenubarItem>
<MenubarItem shortcut="⌘⇧Z">Redo</MenubarItem>
</MenubarContent>
</MenubarMenu>
</Menubar>Showcase
When to use
Reach for Menubar when building desktop-style application shells — editors, design tools, IDE-like products. The pattern users expect: a horizontal strip of top-level triggers (File, Edit, View, Help), each opening a vertical dropdown with commands, shortcuts, separators, submenus.
If you want website navigation instead — logo, nav items, mega-menus — use NavigationMenu. If you only need a single dropdown attached to a button, use DropdownMenu.
Behaviour
- Single open at a time — opening one menu closes any other
- Hover-switch — once any menu is open, hovering a sibling trigger opens it (classic menubar UX)
- Arrow-key roving focus —
ArrowLeft/ArrowRightmove between top-level triggers, withloopfor wrapping (RTL flips direction) - Type-ahead — type a letter to focus the matching item inside an open menu (Base UI built-in)
- Escape closes — and returns focus to the trigger
API Reference
Menubar props
| Prop | Type | Default | Description |
|---|---|---|---|
size | "xs" | "sm" | "md" | "lg" | "xl" | "md" | Scales triggers, padding, gap, and dropdown content |
variant | "solid" | "outline" | "ghost" | "floating" | "solid" | Bar visual treatment — solid (filled), outline (bordered), ghost (no chrome), floating (bordered + shadow) |
rounded | "none" | "sm" | "md" | "lg" | "full" | "md" | Bar corner radius |
intent | "none" | "primary" | "none" | Tints the active menu's trigger |
dir | "ltr" | "rtl" | "ltr" | Flips arrow-key navigation and submenu chevrons |
value | string | null | — | Controlled open menu value |
defaultValue | string | null | null | Uncontrolled initial open menu value |
onValueChange | (value: string | null) => void | — | Called when the open menu changes |
loop | boolean | true | Wrap arrow-key focus from last to first trigger |
MenubarMenu props
| Prop | Type | Description |
|---|---|---|
value | string | Unique identifier for this menu — used to control open state |
children | ReactNode | A MenubarTrigger followed by a MenubarContent |
MenubarTrigger props
| Prop | Type | Description |
|---|---|---|
leadingIcon | ReactNode | Icon before the label |
trailingIcon | ReactNode | Icon after the label |
Renders a <button>. Accepts all standard button HTML attributes plus the disabled prop.
MenubarContent props
| Prop | Type | Default | Description |
|---|---|---|---|
size | MenubarSize | inherited | Override dropdown size — defaults to the bar's size |
width | "narrow" | "default" | "wide" | "default" | Constrain dropdown width |
side | "top" | "bottom" | "left" | "right" | "bottom" | Anchor side |
align | "start" | "center" | "end" | "start" | Anchor alignment |
sideOffset | number | 6 | Pixel offset from the trigger |
alignOffset | number | — | Alignment offset |
MenubarItem props
| Prop | Type | Description |
|---|---|---|
inset | boolean | Reserve space for an indicator on the start side |
leadingIcon | ReactNode | Icon before the label |
trailingIcon | ReactNode | Icon after the label |
shortcut | string | Keyboard shortcut badge (e.g. "⌘K") |
description | string | Secondary line below the label |
intent | "none" | "error" | error styles the item as destructive |
disabled | boolean | Disables the item |
onSelect | (event) => void | Called when activated |
MenubarCheckboxItem props
checked, onCheckedChange, plus all MenubarItem props. Renders a check indicator on the start side when checked.
MenubarRadioGroup + MenubarRadioItem props
MenubarRadioGroup takes value and onValueChange. Each MenubarRadioItem takes a value and shows a filled circle when selected.
MenubarSub / MenubarSubTrigger / MenubarSubContent
Composed exactly like the parent — MenubarSub wraps the pair, MenubarSubTrigger shows a chevron (auto-flipped in RTL), MenubarSubContent opens to the side.
MenubarLabel, MenubarSeparator, MenubarShortcut, MenubarGroup
Layout primitives — MenubarLabel for section headings, MenubarSeparator for hairlines, MenubarShortcut for inline shortcut badges (also auto-rendered when an item has a shortcut prop), MenubarGroup for grouping items semantically.
Notes
- Built by composing
@base-ui/react/menuinstances — Base UI does not ship a dedicatedmenubarprimitive, so the bar-level orchestration (shared open state, hover-switch, arrow-key roving focus) is implemented in this component. - Each
MenubarMenuis a controlledMenu.Rootdriven by the bar's open value. This means you can fully control the bar by liftingvalue/onValueChangeto your own state. - For a single dropdown attached to a button, use
DropdownMenu. For website primary navigation with mega-menus, useNavigationMenu.
Navigation Menu
A full top-bar navigation pattern — logo, centre menu with mega-menu popups, and right-aligned action slots for language selector and auth CTAs. Ships two desktop trigger treatments (`pill`, `underline`), a `mode="mobile"` variant with a right-side drawer + submenu drill-in, richer mega-menu rows (tag + badge), and a theme-aware logo that swaps between light and dark sources. Built on @base-ui/react with 5 sizes, 5 rounded options, and LTR/RTL support.
Bottom Nav
Mobile bottom navigation bar in two styles — a full-width dock and an iOS-style floating pill. Controlled or uncontrolled active state. Badge support (dot or count). LTR and RTL.