Menubar
The strip of words at the top of an application (File, Edit, View), each of which opens a menu. Once one is open, moving along the strip walks through the others rather than closing the one you left.
import { Menubar, MenubarMenu, MenuItem, MenuSeparator } from 'neba';
<Menubar>
<MenubarMenu label="File">
<MenuItem shortcut="⌘N">New file</MenuItem>
<MenuSeparator />
<MenuItem>Open…</MenuItem>
</MenubarMenu>
</Menubar>;Props
| Prop | Type | Default | Description |
|---|---|---|---|
| sizeshared | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'md' | The height and type scale of the words. Its own ladder, one rung below the control heights at every step |
| colorshared | 'primary' | 'secondary' | 'success' | 'warning' | 'danger' | 'info' | 'primary' | The role the word of an open menu carries |
| densityshared | 'default' | 'compact' | 'default' | The horizontal padding of the words and nothing else |
| orientationshared | 'horizontal' | 'vertical' | 'horizontal' | Which way the bar runs. The arrow keys follow it |
| modal | boolean | true | Whether an open menu takes the page away |
| loopFocus | boolean | true | Whether the arrow keys wrap around at the ends of the bar |
| disabled | boolean | false | Disables every menu on the bar at once |
| children | ReactNode | — | The menus |
Every native <div> attribute passes through, apart from color.
It draws no surface of its own. A menu bar sits on something (a Toolbar, a WindowPane's title bar, a Header), and a sheet under a strip that is already on a sheet is two sheets.
MenubarMenu
| Prop | Type | Default | Description |
|---|---|---|---|
| label * | ReactNode | — | The word on the bar |
| startIcon | ReactNode | — | Content before the label. Sized in em, so it tracks it |
| disabled | boolean | false | Unavailable. The word stays on the bar and opens nothing |
| children | ReactNode | — | The rows, written exactly as they are inside a Menu |
The rows are the same MenuItem, MenuSeparator, MenuGroup, MenuCheckboxItem, MenuRadioGroup and MenuSubmenu a Menu takes, because it is the same menu. size, color and density belong to the bar and are not repeated here.
Examples
Nested and checkable rows
Everything a Menu can hold, a menu on the bar can hold: submenus, groups, checkboxes and radio rows.
size
Its own ladder, one rung below the control heights at every step: a menu bar is a strip of words rather than a row of buttons, and it usually sits inside something that already has a height.
import { Menubar, MenubarMenu, MenuItem } from 'neba';
const sizes = ['xs', 'sm', 'md', 'lg'] as const;
export default function MenubarSizes() {
return (
<div className="flex flex-col items-start gap-4">
{sizes.map((size) => (
<Menubar key={size} size={size} aria-label={size}>
<MenubarMenu label="File">
<MenuItem>New file</MenuItem>
</MenubarMenu>
<MenubarMenu label="Edit">
<MenuItem>Undo</MenuItem>
</MenubarMenu>
<MenubarMenu label="View">
<MenuItem>Sidebar</MenuItem>
</MenubarMenu>
</Menubar>
))}
</div>
);
}orientation
vertical stacks the words instead, and the arrow keys follow.
import { Menubar, MenubarMenu, MenuItem } from 'neba';
export default function MenubarOrientation() {
return (
<Menubar orientation="vertical" size="sm" aria-label="Sections" className="w-40">
<MenubarMenu label="Project">
<MenuItem>Settings</MenuItem>
<MenuItem>Members</MenuItem>
</MenubarMenu>
<MenubarMenu label="Deploys">
<MenuItem>Production</MenuItem>
<MenuItem>Preview</MenuItem>
</MenubarMenu>
<MenubarMenu label="Billing">
<MenuItem>Invoices</MenuItem>
</MenubarMenu>
</Menubar>
);
}On a window
import { Menubar, MenubarMenu, MenuItem, MenuSeparator, Typography, WindowPane } from 'neba';
export default function MenubarWindow() {
return (
<WindowPane os="windows11" title="notes.txt" className="w-full max-w-lg" height={220}>
<div className="flex h-full flex-col">
<Menubar size="xs" className="border-b border-(--neba-border) px-1 py-0.5">
<MenubarMenu label="File">
<MenuItem>New</MenuItem>
<MenuSeparator />
<MenuItem>Exit</MenuItem>
</MenubarMenu>
<MenubarMenu label="Edit">
<MenuItem>Find…</MenuItem>
</MenubarMenu>
<MenubarMenu label="Format">
<MenuItem>Word wrap</MenuItem>
</MenubarMenu>
</Menubar>
<div className="p-3">
<Typography level="body">
The strip sits on the window, not on a sheet of its own.
</Typography>
</div>
</div>
</WindowPane>
);
}Accessibility
- Renders
role="menubar"with each word amenuitemthat owns a menu. - The whole bar is one tab stop; the arrow keys move between the words and into the rows, and typeahead works in both.
- Give the bar an
aria-labelwhere a page holds more than one.