Menubar

Pro

The application menu bar — File · Edit · View. One tab stop with a roving tabindex, Left/Right between menus that carries the open menu along, hover that switches only once something is open, and first-letter type-ahead. The panels are Dropdown Menu, so portalling, flipping and the in-panel keyboard model are shared rather than copied.

</>sv-menubar menumenubarapplicationkeyboard
import { SvMenubarComponent } from '@styloviz-pro/overlays';

Demo & usage

Basic usage

Pro

Usage example — open the gallery for the full interactive demo.

Pro

An interactive demo for this component lives in the gallery.

Open live demo

More examples

The menus

Pro

Checkbox items that keep the menu open

Pro

Opened from your own shortcut

Pro

Letting the bar own its shortcuts

Pro

When to use

  • An application shell that needs File / Edit / View — an editor, an IDE-like tool, a design surface.
  • A dense toolbar where the same commands need keyboard access and a discoverable home.
  • For a single button that drops a list of actions, use Dropdown Menu. For right-click, use Context Menu.

Async states

None — this component has nothing to load, so it has no loading, empty or error state to drive.

Inputs

NameTypeDefaultDescription
menusreadonly MenubarMenu[][]The top-level menus, left to right.
sizeMenubarSize'md'Type scale and density.
menuSizeDropdownMenuSize'md'Panel size passed through to each `sv-dropdown-menu`.
ariaLabelstring'Application'Accessible name of the bar itself, e.g. `Editor`. A page with more than one menubar — an app bar plus a per-panel one — is two unnamed "menu bar"s in the landmark list without this.
disabledbooleanfalseNothing in the bar opens.
customClassstring''Extra classes on the bar.
registerShortcutsbooleanfalseRegister every item's `keys` so pressing one fires `(itemClick)`.
shortcutScopeSvShortcutScope'global'Which band the item bindings register in.
openMenuIdstring | null (two-way)nullThe open menu, or `null`. Two-way bindable, so a host can open one from a shortcut of its own (`Alt+F`) or close everything on route change. ONE id rather than a flag per menu: two menus open at once is not a state this widget has, and modelling it as a set would make it representable.

Outputs

EventPayload typeDescription
itemClickMenubarItemClickAn item was chosen, with the menu it came from.
openedstringThe bar opened a menu (any means).
closedvoidEverything closed.
shortcutConflictsreadonly MenubarShortcutConflict[]Two or more items declare the same binding. Reported whether or not `registerShortcuts` is on: two File-menu items both claiming ⌘N is a bug in the menu definition either way, and only one of them could ever run from it.
openMenuIdChangestring | nullEmits the new `openMenuId` whenever it changes — the output half of `[(openMenuId)]`.

Customization & theming

  • Feed `menus` with either flat `items` or `groups` per menu — the same item shape Dropdown Menu takes, including icons, shortcuts, badges, dividers, checkbox/radio types and `danger`.
  • `size` sets the bar's own density; `menuSize` is passed through to the panels.
  • Two-way bind `[(openMenuId)]` to open a menu from a shortcut of your own or close everything on navigation.
  • `disabled` on the bar or on a single menu; disabled menus are skipped by the arrow keys rather than focused and refused.
  • Shortcuts it actually owns: an item's `keys` (`'mod+n'`) renders itself for the running platform, and `[registerShortcuts]` binds it through the shared registry, where `[shortcutScope]` decides whether an overlay's binding outranks it. Duplicates are reported through `(shortcutConflicts)` whether or not anything is bound. Off by default, because an app with a menubar has usually bound these keys already.

Best practices

  • Do: Keep top-level labels to one word — they are targets on a shared row, and the first letter is the type-ahead key.
  • Do: Give every item `keys` (e.g. `'mod+n'`) rather than a `shortcut` glyph string — the menu bar is where users go to LEARN shortcuts, and `keys` renders itself as ⌘N or Ctrl N for the platform they are actually on. `shortcut` is display-only, binds nothing, and shows ⌘N to a Windows user exactly as typed.
  • Do: Turn on `[registerShortcuts]` if the app does not already bind these keys itself, so the bar arbitrates what it draws instead of just drawing it. Duplicate `keys` are reported through `(shortcutConflicts)` either way — two items both claiming ⌘N is a bug in the menu definition, and only one of them could ever run.
  • Do: Set `keepOpen` on checkbox items so a run of toggles does not slam the menu shut on the first one.
  • Don't: Don't use it as navigation — a menubar announces itself as commands, not as links: items are reached by arrow keys instead of Tab and are missing from a screen reader's links list. Use Mega Menu or a nav bar inside a `<nav>` for going places. In dev mode the bar warns when any item has an `href`.
  • Don't: Don't reach for a menubar to expose one or two actions — it is a commitment to an application keyboard model (roving tabindex, type-ahead, cross-menu arrows). Two buttons are two buttons.

Accessibility

  • A real `role="menubar"` owning `role="menuitem"` buttons — the Dropdown Menu trigger wrapper is made presentational so the ownership assistive technology walks is not broken by a layout div.
  • ONE tab stop for the whole bar via a roving tabindex; Left/Right move between menus (wrapping, skipping disabled), Home/End jump to the ends, Down/Enter/Space open, Escape closes and returns focus to the trigger.
  • With a menu open, moving along the bar carries the open menu with it — and the keys the open panel owns (Up/Down, Enter, type-ahead over items) are left to the panel rather than handled twice.
  • The panel keeps DOM focus on the trigger and moves a virtual cursor, so `aria-activedescendant` and `aria-owns` are published from the trigger button — the element that actually has focus.

Feedback on Menubar

Spotted a gap in this page, or something that didn't work as described? Comments are GitHub Discussions in the public styloviz/community repo, so posting needs a GitHub account.

Loads giscus.app and GitHub — nothing is fetched until you click.