Menubar

Manual until a YAML contract lands in monochrome/spec/components/.

Horizontal strip of menu triggers (File / Edit / View style). Builds on the same core as Menu: each trigger/popover pair uses mct:menu: / mcc:menu:, arrow keys move between triggers, and an open menu follows the cursor across the bar.

Differences from a standalone Menu:

  • Container role="menubar"
  • Roving tabindex: exactly one trigger has tabindex="0", every other trigger tabindex="-1" (one Tab stop for the bar)
  • Triggers use role="menuitem"
  • Wrappers expose Menubar.* (Menu item helpers are re-exported). Authors mark the Tab-stop menu with first (React/Vue)

Composition

Root (ul role="menubar")
  Menu (li role="none")
    Trigger (role="menuitem")
    Popover (ul role="menu" popover="manual")
      Item | CheckboxItem | RadioItem | Label | Separator | Group

Usage

HTML

html
<ul role="menubar">
  <li role="none">
    <button type="button" role="menuitem" id="mct:menu:file" aria-controls="mcc:menu:file" aria-expanded="false" aria-haspopup="menu" tabindex="0">
      File
    </button>
    <ul role="menu" id="mcc:menu:file" aria-labelledby="mct:menu:file" aria-hidden="true" popover="manual">
      <li role="none"><button type="button" role="menuitem" tabindex="-1">New File</button></li>
      <li role="none"><button type="button" role="menuitem" tabindex="-1">Open...</button></li>
      <li role="none"><button type="button" role="menuitem" tabindex="-1">Save</button></li>
    </ul>
  </li>
  <li role="none">
    <button type="button" role="menuitem" id="mct:menu:edit" aria-controls="mcc:menu:edit" aria-expanded="false" aria-haspopup="menu" tabindex="-1">
      Edit
    </button>
    <ul role="menu" id="mcc:menu:edit" aria-labelledby="mct:menu:edit" aria-hidden="true" popover="manual">
      <li role="none"><button type="button" role="menuitem" tabindex="-1">Undo</button></li>
      <li role="none"><button type="button" role="menuitem" tabindex="-1">Redo</button></li>
    </ul>
  </li>
</ul>

React

jsx
import { Menubar } from "@monochrome-ui/react"

<Menubar.Root>
  <Menubar.Menu first>
    <Menubar.Trigger>File</Menubar.Trigger>
    <Menubar.Popover>
      <Menubar.Item>New File</Menubar.Item>
      <Menubar.Item>Open...</Menubar.Item>
      <Menubar.Item>Save</Menubar.Item>
    </Menubar.Popover>
  </Menubar.Menu>
  <Menubar.Menu>
    <Menubar.Trigger>Edit</Menubar.Trigger>
    <Menubar.Popover>
      <Menubar.Item>Undo</Menubar.Item>
      <Menubar.Item>Redo</Menubar.Item>
    </Menubar.Popover>
  </Menubar.Menu>
</Menubar.Root>

Vue

vue
<script setup lang="ts">
import { Menubar } from "@monochrome-ui/vue"
</script>

<template>
  <Menubar.Root>
    <Menubar.Menu first>
      <Menubar.Trigger>File</Menubar.Trigger>
      <Menubar.Popover>
        <Menubar.Item>New File</Menubar.Item>
        <Menubar.Item>Open...</Menubar.Item>
        <Menubar.Item>Save</Menubar.Item>
      </Menubar.Popover>
    </Menubar.Menu>
    <Menubar.Menu>
      <Menubar.Trigger>Edit</Menubar.Trigger>
      <Menubar.Popover>
        <Menubar.Item>Undo</Menubar.Item>
        <Menubar.Item>Redo</Menubar.Item>
      </Menubar.Popover>
    </Menubar.Menu>
  </Menubar.Root>
</template>

Parts

Root

Required. Element: ul with role="menubar". Children: Menu (and optional top-level items after the menu marked first).

Required per top-level entry. Element: li role="none". Provides slot context for Trigger + Popover.

Kind Name Type Default Description
prop first boolean false When true, this menu's Trigger gets tabindex="0" (the bar's Tab stop). Exactly one top-level Menu should set first. Submenus use Group (never first). HTML authors set tabindex on the trigger by hand instead.

Trigger / Popover

Same id and ARIA contract as Menu (mct:menu:<id> / mcc:menu:<id>, aria-haspopup="menu", popover="manual"), with role="menuitem" on the trigger and roving tabindex.

Kind Name Type Default Description
prop disabled boolean false On Trigger; emits aria-disabled.

Group

Submenu inside a popover: wraps its own Trigger + Popover pair (li role="none", new id). Same pattern as Menu.Group.

Item, CheckboxItem, RadioItem, Label, Separator

Same behavior and markup as Menu. React/Vue re-export Menu helpers as Menubar.Item, etc.

Notes

  • Ids: Same mct:menu / mcc:menu scheme as Menu (not a separate prefix).
  • Hover across bar: With a menu open, moving to another menubar trigger opens that menu (chord switching).
  • Submenus: Nest via Group; ArrowRight opens, ArrowLeft closes. Safety triangle applies as in Menu.
  • Selection items: CheckboxItem / RadioItem / Label / Separator work exactly as in Menu.

Keyboard

Key Context Behavior
Tab Bar Lands on the tabindex="0" trigger only
ArrowLeft / ArrowRight Trigger or open menu Move between menubar triggers; if a menu was open, open the destination menu
ArrowDown / ArrowUp Closed trigger Open menu; focus first / last item
ArrowDown / ArrowUp Inside menu Roving among items
ArrowRight Submenu trigger Open submenu
ArrowLeft Inside submenu Close submenu
Home / End Inside menu First / last item
a-z Inside menu Typeahead
Escape Open Close topmost layer
Tab Open menu Close all menus

See also