---
title: "Menubar"
description: "Keeps an application's commands within reach in one persistent row of named menus (File, Edit, View…), each opening a menu below its title, with the arrow keys moving along the row and into each menu."
url: "https://tanrei.chnotchy.com/components/menubar/"
last_updated: 2026-10-23T21:17:12.000Z
---

# Menubar

> Keeps an application's commands within reach in one persistent row of named menus (File, Edit, View…), each opening a menu below its title, with the arrow keys moving along the row and into each menu.

## Overview

### What a menubar is not

Read this before you reach for it. A menubar is for the commands of an application, and for little else.

- **It is not a site’s navigation.** A row of sections with drop-downs is navigation: links, in a navigation landmark, reached with Tab. A menubar tells assistive technology that the arrow keys, not Tab, move through everything inside it, and that every entry is a command. A person who meets that on a set of page links is misled. Use an [app bar](https://tanrei.chnotchy.com/components/app-bar/), a [navigation bar](https://tanrei.chnotchy.com/components/navigation-bar/) or a [navigation drawer](https://tanrei.chnotchy.com/components/navigation-drawer/).
- **It is not a toolbar.** A [toolbar](https://tanrei.chnotchy.com/components/toolbar/) holds buttons that act when pressed. A menubar is a row of menus. It may hold one or two entries that act by themselves ([below](https://tanrei.chnotchy.com/components/menubar/#entries-that-act)), and a row of those alone is a toolbar. Moving along the bar never runs anything, so a person can explore it safely.
- **It is not a row of buttons that each open a menu.** That row looks the same and fails in use: its arrow keys never carry an open menu along, a pointer does not move the open menu with it, and assistive technology hears separate buttons where there is one menu in two levels.
- **It is not tabs.** No title is ever selected. Its menu closes and nothing stays chosen.
- **It is not one menu.** A short set of options belongs in one [menu](https://tanrei.chnotchy.com/components/menu/) opened from a button.

### What it is

A product that is an application — an editor, a spreadsheet, a drawing or planning tool — has more commands than its screen can show as buttons. A menubar is the place where every one of them is, under a few names a person learns once, each with its shortcut beside it.

It is a row of titles that is always in view. Each title opens a Tanrei [Menu](https://tanrei.chnotchy.com/components/menu/) below it, with the menu’s own items: actions, link items, checkbox and radio items, groups, submenus and shortcuts. Beside the titles the row may hold a bar item: an action that runs at once, or a link. The row is one stop in the focus order. The arrow keys move along it and into a menu, and from inside a menu they go straight on to the neighbouring entry.

The bar has no fill, edge or elevation of its own. You place it, normally at the top of the window in chrome that is already there.

On the web it is `<tanrei-menubar>` around `<tanrei-menubar-menu>` elements, with `<tanrei-menubar-item>` for an entry that acts. The other platforms have not implemented it yet.

### Usage

Give the bar a `label`, and each menu a `label` of one or two words. Put the menu’s items inside it exactly as you would inside a menu. Listen for the items’ own events: the bar adds none to them.

Each menu has an `open` of its own. The bar sets it and fires `toggle`, so you do not keep track of which menu is open. You may set it yourself to open a menu from a key of your own.

**Web**

```html
<tanrei-menubar label="Application menu" overflow-label="More menus">
  <tanrei-menubar-menu label="File">
    <tanrei-menu-item label="New" shortcut="mod+n"></tanrei-menu-item>
    <tanrei-menu-item label="Open…" shortcut="mod+o"></tanrei-menu-item>
    <tanrei-submenu label="Open recent">
      <tanrei-menu-item label="Quarterly report"></tanrei-menu-item>
    </tanrei-submenu>
    <tanrei-menu-item label="Save" shortcut="mod+s"></tanrei-menu-item>
  </tanrei-menubar-menu>
  <tanrei-menubar-menu label="View">
    <tanrei-menu-checkbox-item label="Ruler" checked></tanrei-menu-checkbox-item>
  </tanrei-menubar-menu>
  <tanrei-menubar-menu label="Format" disabled>…</tanrei-menubar-menu>
</tanrei-menubar>

<script type="module">
  import '@tanrei/web/components/menubar';

  const bar = document.querySelector('tanrei-menubar');
  // One listener takes every item's click. After a command, move focus to what it acts on.
  bar.addEventListener('click', (event) => {
    if (event.target.localName !== 'tanrei-menu-item') return;
    run(event.target.label);
    editor.focus();
  });
  // The shortcuts an item shows are yours to bind. So is a key that opens a menu.
  addEventListener('keydown', (event) => {
    if (event.altKey && event.key === 'f') bar.querySelector('[label="File"]').open = true;
  });
</script>

<!-- Reserve the bar's height before the element is defined, so the page does not move. -->
<style>
  tanrei-menubar:not(:defined) {
    display: block;
    min-block-size: calc(var(--tanrei-comp-menubar-container-height) + 2 * var(--tanrei-comp-menubar-bar-padding-block));
  }
</style>
```

**React**

```tsx
import { Menubar, MenubarMenu, MenuItem, MenuCheckboxItem, Submenu } from '@tanrei/react';

<Menubar label="Application menu" overflowLabel="More menus">
  <MenubarMenu label="File" onToggle={(event) => track('File', event.detail.open)}>
    <MenuItem label="New" shortcut={['mod+n']} onClick={newDocument} />
    <MenuItem label="Open…" shortcut={['mod+o']} onClick={openDocument} />
    <Submenu label="Open recent">
      {recent.map((file) => <MenuItem key={file.id} label={file.name} onClick={() => open(file)} />)}
    </Submenu>
  </MenubarMenu>
  <MenubarMenu label="View">
    <MenuCheckboxItem label="Ruler" checked={ruler} onChange={(event) => setRuler(event.detail.checked)} />
  </MenubarMenu>
  <MenubarMenu label="Format" disabled={!selection}>…</MenubarMenu>
</Menubar>
```

On the web the titles and the actions are not drawn until the script has run: their words are attributes, and every command is your script. A link item is different. It is your own anchor, so it is a link that works before the script runs and where it never does.

### Entries that act

Before you use a bar item, read when not to use one. A bar item looks exactly like a title that opens a menu, so each one costs a person a moment of doubt about what a press will do.

- **Not for most commands.** A command belongs in a menu, where it has a shortcut, an icon and neighbours that explain it. Keep a bar item for the one or two things a person wants in a single press (“Run”, “Share”) or the one or two places they go (“Documentation”).
- **Not for anything that cannot be undone.** A bar item asks nothing before it runs and has no destructive look. A command that deletes or discards belongs in a menu.
- **Not for a choice that is switched on and off.** A title has no place for a check. Put it in a menu of the same bar, as a checkbox or a radio item.
- **Not as the whole bar.** A row of actions alone is a [toolbar](https://tanrei.chnotchy.com/components/toolbar/), and a row of links alone is navigation. Either is drawn and works, and is reported in debug builds.
- **Not with a word that hides what it does.** In a bar that holds both, each menu’s title ends in a small downward chevron and a bar item has none, but the label still says what a press does. Name an action with a verb, and a link with the place it leads to.

An action is `<tanrei-menubar-item label="Run">`. A press, Enter or Space fires its `click` once. If a menu of the bar is open it closes first, so your handler runs with no menu shown. Focus stays on the bar item unless your handler moves it.

A link item is the same element around your own anchor: `<tanrei-menubar-item><a href="/docs/">Documentation</a></tanrei-menubar-item>`. Everything that makes it a link belongs to the anchor: the anchor’s text is the label, and `href`, `target`, `rel` and `aria-current="page"` are written on the anchor. The element draws a title around it and makes it one stop of the bar’s keys.

- `click` is the anchor’s own click. Cancel it with `preventDefault()` and nothing is followed, which is all a client-side router needs. A router’s own link component works as the child.
- A click with a modifier key, a middle click and the link’s context menu are the browser’s, as on any link. Space follows a link item as Enter does, because every other entry of the row answers Space.
- `target="_blank"` draws the icon set’s `open_in_new` after the label and adds `noopener`. Say it in words with `target-label` on the element, or once for the product with `setWords({ targetLabel: … })`.
- `aria-current="page"` on the anchor marks the page a person is on. It is drawn with the fill a menu draws for the row a person is on, at its label’s own weight, so that the current page looks the same in the bar and in a menu. It never looks like the title of an open menu. You set it, and the bar never does.
- A disabled link item is `disabled` on the element and an anchor without `href`.

**Web**

```html
<link rel="stylesheet" href="@tanrei/web/menubar.css" />

<tanrei-menubar label="Application menu" overflow-label="More">
  <tanrei-menubar-menu label="File">…</tanrei-menubar-menu>
  <tanrei-menubar-menu label="Edit">…</tanrei-menubar-menu>
  <tanrei-menubar-item label="Run"></tanrei-menubar-item>
  <tanrei-menubar-item><a href="/docs/">Documentation</a></tanrei-menubar-item>
  <tanrei-menubar-item target-label="opens in a new tab">
    <a href="https://example.com/source" target="_blank">Source</a>
  </tanrei-menubar-item>
  <tanrei-menubar-item><a href="/history/" aria-current="page">History</a></tanrei-menubar-item>
</tanrei-menubar>

<script type="module">
  import '@tanrei/web/components/menubar';

  // An action: its own click, in the row or folded into the overflow item.
  document.querySelector('tanrei-menubar-item[label="Run"]').addEventListener('click', run);
  // A link item: the anchor's click. Cancel it and the navigation is yours.
  document.querySelector('tanrei-menubar-item > a[href="/docs/"]').addEventListener('click', (event) => {
    event.preventDefault();
    router.push('/docs/');
  });
</script>
```

**React**

```tsx
import { Menubar, MenubarMenu, MenubarItem } from '@tanrei/react';
import { Link } from 'your-router';

<Menubar label="Application menu" overflowLabel="More">
  <MenubarMenu label="File">…</MenubarMenu>
  <MenubarItem label="Run" onClick={run} />
  {/* The router's own link is the child: it renders the anchor and takes the navigation. */}
  <MenubarItem><Link href="/docs/">Documentation</Link></MenubarItem>
  <MenubarItem targetLabel="opens in a new tab">
    <a href="https://example.com/source" target="_blank">Source</a>
  </MenubarItem>
</Menubar>
```

`@tanrei/web/menubar.css` is for the time before the script runs, and for a reader whose browser runs none. It lays the link items out as a row in the bar’s place, in a title’s text style, and each is followed and reached with Tab as any link. The menus and the actions are not there yet. When the bar runs it takes the same anchors where they stand.

## Specs

- Category: Selection
- Level: composed
- Listing: default
- Built from: Menu
- Page: https://tanrei.chnotchy.com/components/menubar/
- Spec: https://github.com/chnotchy/tanrei/blob/main/specs/menubar.spec.json

### Availability

| Design system | Has it | Notes |
| --- | --- | --- |
| Tanrei (`tanrei`) | Yes | — |
| Cupertino (Apple HIG-inspired) (`cupertino`) | Yes | — |
| M3 Expressive-like (Material 3 Expressive-inspired) (`m3-expressive-like`) | Yes | — |
| M3-like (Material 3-inspired) (`m3-like`) | Yes | — |

### Platforms

- Web: the element `<tanrei-menubar>`, registered by importing `@tanrei/web` (or only its own module, `@tanrei/web/components/menubar`).
- React: `Menubar` from `@tanrei/react`.

| Platform | Name | Status |
| --- | --- | --- |
| Web | `tanrei-menubar` | lagging |
| SwiftUI | `TanreiMenubar` | planned |
| Jetpack Compose | `TanreiMenubar` | planned |
| Flutter | `TanreiMenubar` | planned |
| React Native | `Menubar` | planned |

Names a platform gives in its own idiom:

| Spec | Web | SwiftUI | Jetpack Compose | Flutter | React Native |
| --- | --- | --- | --- | --- | --- |
| `label` (prop) | `label` | `label` | `contentDescription` | `semanticLabel` | `accessibilityLabel` |
| `overflowLabel` (prop) | `overflowLabel` | `overflowLabel` | `overflowContentDescription` | `overflowSemanticLabel` | `overflowAccessibilityLabel` |

Statuses: `planned` — In the inventory. Nothing shippable exists yet. `lagging` — An implementation of an earlier spec exists; it has not caught up with the current one. `alpha` — Implemented with tests. The API may still change. `beta` — Feature complete and at parity. Only fixes are expected. `stable` — Covered by semantic versioning. `deprecated` — Still shipped; scheduled for removal.

### Anatomy

- `bar`: The row itself: its fill (transparent in the default system, so the chrome it stands on shows through), its paddings and the gap between titles. It spans the inline size its parent gives it and is placed by the product.
- `container`: One entry's container — a menu's title or a bar item: the part that is pressed and that carries hover, focus and press, and the fill of the title whose menu is open.
- `label`: An entry's text and accessible name: a menu's label for its title, a bar item's own label, on one line, never cut.
- `menu` (optional): The surface a title opens: a Tanrei Menu below the title, drawn from the menu's own tokens and holding the menu's own items — actions, link items, checkbox and radio items, groups, submenus and shortcuts.
- `overflow-item` (optional): The last title of a row that cannot hold every title: the glyph more_horiz of the system's icon set in a title's container. Its menu holds the menus that were folded out of the row, each as a submenu. Drawn only while something is folded.
- `icon` (optional): The overflow item's glyph, the one entry that is not a word.
- `mark` (optional): The glyph open_in_new of the system's icon set after the label of a link item that opens a new context (MBR-37). Hidden from assistive technology; the link item's targetLabel says what it shows.
- `indicator` (optional): The glyph expand_more of the system's icon set after a menu's title while the bar also holds bar items (MBR-47): it tells an entry that opens a menu from one that acts at once. Hidden from assistive technology, which is told by the title's own popup state.
- `focus-ring`: The system's keyboard focus indicator around a title's container.

### Props

| Prop | Type | Default | Web attribute | Description |
| --- | --- | --- | --- | --- |
| `label` | `string` | `""` | `label` | Names the bar for assistive technology ("Application menu"), in the product's language. Never drawn. Required. It is this bar's own name and is not read from the product's words. |
| `overflowLabel` | `string` | `""` | `overflow-label` | The accessible name of the overflow item ("More menus", or "More" where bar items may fold into it too), in the product's language. Never drawn. Needed whenever the bar may be narrower than its entries, which on the web is always. |

### Item: `menu`

One menu of the bar: its title in the row and the items that open below it. Its items are the menu component's own item kinds (item, checkbox-item, radio-item, submenu and group, as the menu spec defines them), which the bar presents in a Tanrei Menu; a fixture cannot fill them.

Names: Web `tanrei-menubar-menu`, SwiftUI `TanreiMenubarMenu`, Jetpack Compose `TanreiMenubarMenu`, Flutter `TanreiMenubarMenu`, React Native `MenubarMenu`.

| Prop | Type | Default | Web attribute | Description |
| --- | --- | --- | --- | --- |
| `label` | `string` | `""` | `label` | The title's text, and the name of the title and of the menu it opens ("File"). Required. One or two words. |
| `open` | `boolean` | `false` | `open` | Whether this menu is shown. It is the menu's own, as a submenu item's is: the bar sets it when the menu is opened or closed and emits toggle; the product may set it to open or close the menu itself. At most one menu of a bar is open. |
| `disabled` | `boolean` | `false` | `disabled` | Prevents the menu from opening. The title stays in the row and reachable with the arrow keys. |

| Event | Description |
| --- | --- |
| `toggle` | The menu was opened or closed by the person — from its title, by the arrow keys from a neighbouring menu, by a pointer moving along the bar, by Escape, Tab, a press outside or an item's activation, or as a submenu of the overflow item. Carries the new open value. Not emitted for a change the product made to open. |

### Item: `item`

A bar item: an entry of the bar that acts by itself instead of opening a menu. It is an action, run at once; with an href it is a link, which goes somewhere. It is the menu's own item kind brought up to the row, with a title's look and none of a row's columns.

Names: Web `tanrei-menubar-item`, SwiftUI `TanreiMenubarItem`, Jetpack Compose `TanreiMenubarItem`, Flutter `TanreiMenubarItem`, React Native `MenubarItem`.

| Prop | Type | Default | Web attribute | Description |
| --- | --- | --- | --- | --- |
| `label` | `string` | `""` | `label` | The bar item's text and its accessible name ("Run", "Documentation"). Required. One or two words that say what it does at once — a verb for an action, the place for a link — because nothing in its look tells it from a title that opens a menu. |
| `disabled` | `boolean` | `false` | `disabled` | Prevents activation. The bar item stays in the row and reachable with the arrow keys, as a disabled title does; a disabled link item cannot be followed (MBR-39). |
| `href` | `string` | `""` | — | The destination: an address as the platform's links take one (a URL; on the web a path or a fragment as well). Not empty, it makes the bar item a link item (a control with a destination is a link): the platform's own link, exposed as a menu item, drawn exactly as an action is and reached with the same keys; a plain activation emits click and opens the destination (MBR-35, MBR-36). Empty, the bar item is an action and the product acts on click. As the menu item's href (MNU-53). |
| `target` | `enum`: `same`, `new` | `"same"` | — | Where the destination opens, as the Button's target. same: where the person is. new: a new context — a new tab or window on the web, outside the current screen elsewhere — which the bar item marks with the glyph open_in_new after its label and says through targetLabel (MBR-37). Ignored without href. |
| `targetLabel` | `string` | `""` | `target-label` | What assistive technology reads after the link item's name while target is new ("opens in a new tab"), as the Button's targetLabel: Tanrei ships no words of its own. Required while target is new; ignored otherwise. |
| `current` | `boolean` | `false` | — | The link item names the place the person is already at (the current page), as the Link's current. It is exposed as the current item, drawn with the fill of the menu's row the person is on (comp.menubar.selected.container.color, which aliases comp.menu.current.container.color) at its label's own weight, and stays a link (MBR-38). The product sets it; the bar never does, and at most one bar item of a bar is current. Ignored without href. |

| Event | Description |
| --- | --- |
| `click` | The bar item was activated by pointer, touch, Enter, Space or assistive technology — in the row or, while it is folded, in the overflow item's menu. A link item emits it before its destination opens; a product that takes the navigation itself (a client-side router) cancels it (MBR-36). |

### States

`enabled`, `disabled`, `hovered`, `focused`, `pressed`

### Accessibility

- Role: `menubar`
- Labeling: label names the bar; it is never drawn. Each title is a menu item named by its menu's label, which also names the menu it opens; it says that it opens a menu, whether that menu is open, whether it is disabled, and where it stands among the bar's titles. A bar item is a menu item named by its own label; it does not say that it opens a menu and has no expanded state, and says whether it is disabled and where it stands among the bar's entries, which are counted together. A link item is the platform's link exposed as a menu item (MBR-35); while its target is new its targetLabel is its description, and while it is current it says so. The overflow item is named by overflowLabel, and the menus folded into it keep their labels as its submenu items, the bar items folded into it as its items. Everything inside a menu is named as the menu's spec says. The overflow item's glyph is decorative.
- Minimum target size: yes

| Keys | Action |
| --- | --- |
| Tab / Shift+Tab | Moves focus into the bar, to the entry focused last or else the first entry, and out of it: the bar is one Tab stop. With a menu open, closes it and moves focus on out of the bar. |
| Right Arrow / Left Arrow on a title or a bar item (mirrored in a right-to-left layout) | Moves focus to the next or previous entry of the row, wrapping at the ends. Disabled entries and the overflow item are reached too. Opens nothing and runs nothing. |
| Home / End on a title or a bar item | Moves focus to the first or last entry. |
| Printable character on a title or a bar item | Moves focus to the next entry whose label begins with it, whatever its letter case. Opens nothing and runs nothing. |
| Enter, Space or Down Arrow on a title | Opens its menu and moves focus to the menu's first enabled item. |
| Up Arrow on a title | Opens its menu and moves focus to the menu's last enabled item. |
| Enter or Space on a bar item | An action: runs it (click); focus stays on the bar item unless the product moved it. A link item: follows the link, Space as Enter does. With a modifier key, Enter on a link item is the platform's (another tab or window). |
| Down Arrow / Up Arrow on a bar item | Nothing: there is no menu to open. The keys are still taken, so the page does not scroll. |
| Down Arrow / Up Arrow, Home / End, printable characters in a menu | The menu's own keys, within the level that holds focus (MNU-7). |
| Right Arrow in a menu (Left Arrow in a right-to-left layout) | On a submenu item, opens its submenu. On any other item, at any level, closes the menu and moves to the next enabled entry: a title's menu is opened, with focus on its first enabled item; a bar item takes focus, and nothing opens or runs (MBR-40). |
| Left Arrow in a menu (Right Arrow in a right-to-left layout) | In a submenu, closes that submenu and returns focus to its item. In the menu's own surface, closes the menu and moves to the previous enabled entry: a title's menu is opened, with focus on its first enabled item; a bar item takes focus, and nothing opens or runs (MBR-40). |
| Enter / Space on an item of a menu | Activates it as the menu says; an action or a link item closes the menu and focus returns to the title. |
| Escape | Closes the innermost open submenu; with none open, closes the menu and returns focus to its title. Does nothing while no menu is open. |

- What it is for: the commands of an application — an editor, a spreadsheet, a drawing or planning tool — in a window wide enough to show several named menus. It is not a site's main navigation with drop-downs: a row of links to pages, always in view, is navigation and belongs in a navigation landmark of links (the menu's own note on link items says the same). A menubar tells assistive technology that the arrow keys, and not Tab, move through everything in it and that every entry is a command; a person who meets that on a set of page links is misled.
- It follows the WAI-ARIA menubar pattern in full: one Tab stop, the horizontal arrow keys along the bar, the vertical ones into and inside a menu, the horizontal ones from inside a menu on to the neighbouring entry, Escape back to the title, type-ahead at both levels, and an entry of the bar that acts by itself — an action or a link. What it leaves out of that pattern: a checkbox or a radio entry directly in the bar. A choice that is switched needs a mark for its state, a title has no place for one, and the menus of the same bar already have it. Exploring the bar still runs nothing: focus arriving, the arrow keys, a typed character and a pointer over an entry never activate it; only a press, Enter or Space does (MBR-33).
- A bar item is for the one or two commands or places that belong beside the menus and are wanted in one press ("Run", "Share", "Documentation"). Nothing in its look tells it from a title that opens a menu, so its label says what it does at once: a verb for an action, the name of the place for a link. A command that deletes something or cannot be undone does not belong on the bar: a bar item has no destructive look and asks nothing before it runs; put it in a menu. A row of bar items with no menu is not a menubar — actions alone are a toolbar, links alone are navigation — and is reported (MBR-44).
- A link item is the platform's own link exposed as a menu item, exactly as the menu's own link item is and for the same reason (MNU-53): a menubar is read by its entries — how many, which one, the arrow keys — and that reading holds only while everything in the row is a menu item; so the role stays, and what makes the entry a link stays underneath it: its address, the browser's context menu and new-tab gestures, a crawler that follows it. Like the menu's, it is a link that Space activates. On the web it is the product's own anchor in the document, so it is a working link before the bar runs and where script does not (MBR-45). current marks the page the person is on among the bar's link items; the product sets it and the bar draws it with the fill a menu draws for the row the person is on, the same in both: it is where the person is, not a menu that is shown, so it never takes the expanded condition's colors.
- A link item that opens a new context is marked by the one rule every link form follows: the glyph open_in_new stands at the control's trailing glyph place, where the control lays out its own content and has such a place. A title's container has one — the overflow item's glyph stands in it — as a button's label has (BTN-24) and a menu's row has in its trailing icon column (MNU-55), which is where a folded link item's mark is drawn; the navigation bar draws none because its cell, an icon over a label, has no such place (NVB-32). Whether a mark is drawn or not, targetLabel says it (MBR-37).
- A bar item's click and the closing of an open menu come in one of two orders, by where the bar item is activated (MBR-33, MBR-36, MBR-43). In the row, the menu that is open belongs to another entry and is closed first, as it is when another title is pressed (MBR-10): the product's handler runs with no menu shown. Folded, the bar item is an item of the overflow item's menu, and its click comes first and the menu closes after it, as for every item of a menu (MNU-6, MBR-15). What a product can rely on in both: one click, on the bar item's own element, before the bar decides where focus rests.
- A bar's menu is to the bar what a submenu item is to a menu: a label, an open value of its own, a disabled value, and a toggle event. The surface it opens is a Tanrei Menu with the menu's own item kinds and tokens. The item kind menu of this spec has no items of its own in the schema because they are another spec's kinds; a fixture therefore draws an open menu empty, as a button with menu's fixtures do, and the tests fill it.
- Focus: the bar is part of the page and a Tab stop like a toolbar. A menu it opens takes focus and returns it to its title when it closes by Escape or by an item; Tab leaves the bar altogether. A bar item opens nothing, so it takes no focus away: after it runs, focus is still on it (MBR-33). After a command the product may move focus to what the command acts on (the document, a dialog it opened) in its handler, and the bar does not take it back (MBR-15).
- Disabled titles stay reachable along the bar with no menu open, so that a screen reader user hears that the menu exists and is unavailable; with a menu open, the horizontal arrow keys pass over them, because those keys then mean 'show me the next menu' and a disabled title has none to show (MBR-13). A disabled bar item is reached and passed over the same way. An enabled bar item is not passed over: the keys land on it, the open menu closes, and from there they go on along the bar without opening anything, because a menu follows focus only while one is shown (MBR-40).
- Keyboard shortcuts shown in the menus are drawn and exposed by the menu through the keyboard shortcut component; the bar binds none (MBR-16). Access keys — an underlined letter per title, a key that jumps to the bar — are left out: they differ by platform, collide with the browser's own on the web, and a letter is chosen per language, which a component that ships no words cannot do. Type-ahead on the bar gives the first-letter jump once focus is there.
- A compact window: the bar folds what does not fit into one overflow item at its end, whose menu holds the folded menus as submenus and the folded bar items as items (MBR-43); when nothing fits it is that one item alone (MBR-21, MBR-22). The keys, the roles and the order are the same at every width, and no command is lost. A product that would rather not show a menubar at all on a phone — commands in an app bar's actions and its 'more' menu are the touch idiom — does not render it there; that is the product's layout and needs nothing from the bar.
- Where the platform has a menu bar of its own outside the window (a desktop system's global bar, a tablet's bar for a hardware keyboard), the product should give its commands to that bar with the platform's own API as well: people look for them there, and its keys are the platform's. Tanrei's menubar is drawn inside the product's window from Tanrei's tokens; it does not fill or replace the system's.
- Contrast: a title's or a bar item's label keeps at least 4.5:1 on the bar in every state of both conditions. The open title's fill supports the open menu beneath it, which is what says a menu is open; the fill is not held to a contrast of its own. The focus ring is the system's and keeps 3:1 against what it is drawn on.
- minimumTarget: a title is 40 high in a bar 48 high in the default system, so its touch target lies inside the bar; a short title ('Go') is narrower than the target and gets the room MBR-17 gives it.

### Behaviour

Requirements in EARS form, each with its stable id.

- **MBR-1** THE menubar SHALL draw one row across the full inline size its parent gives it: comp.menubar.bar.color behind the whole row, and on it the titles of its menus, one for each menu in the order given, from the start edge, comp.menubar.bar.gap apart, inset by comp.menubar.bar.padding-inline from the row's start and end edges and by comp.menubar.bar.padding-block above and below. It SHALL NOT position itself, stick to an edge, raise itself or draw an edge of its own: the product places it, normally at the top of its window or in the chrome that is already there, and the bar stays in view because that chrome does.
- **MBR-2** THE menubar SHALL draw each title as a container at least comp.menubar.container.height tall and as wide as its label with comp.menubar.container.padding-inline on each side, with corners comp.menubar.container.shape, each at most half the container's height, and its label centered in it on one line in comp.menubar.label.typescale; it SHALL NOT wrap, shrink or truncate a title's label: a title that the row has no room for is folded whole (MBR-21).
- **MBR-3** THE menubar SHALL draw a title from the condition it is in: expanded while its menu is open, otherwise unselected; a bar item from the unselected condition, and a link item that is current from the selected one (MBR-38). WHILE a title is at rest its container SHALL take the container color of its condition (comp.menubar.unselected.container.color, comp.menubar.selected.container.color, comp.menubar.expanded.container.color) drawn over the bar, and its label the label color of its condition (comp.menubar.unselected.label.color, comp.menubar.selected.label.color, comp.menubar.expanded.label.color). No title is selected: the expanded condition says which menu is shown now and ends when that menu closes, and the selected condition is the current page's alone (MBR-38).
- **MBR-4** WHILE a title is hovered, keyboard-focused or pressed THE menubar SHALL render its container, label, the overflow item's glyph and opacity from the component tokens of its condition in the highest-precedence active state, with precedence pressed over focused over hovered; focus gained by pointer or touch SHALL NOT select the focused state.
- **MBR-5** WHEN a title receives keyboard focus THE menubar SHALL show the focus ring around the title's container without animation; focus gained by pointer or touch SHALL NOT show it. The bar SHALL leave room for the ring: it SHALL NOT clip it at its own edges.
- **MBR-6** WHEN the menubar title is pressed by pointer, touch, Enter or Space THE menubar title SHALL show the pressed state without delay and SHALL keep it visible for at least sys.motion.duration.press-hold, even when the press ends sooner.
- **MBR-7** WHILE pressed THE menubar title SHALL answer as sys.behavior.pressed-feedback names: overlay applies the pressed tokens to the whole container at once; ripple grows the pressed state layer from the point of contact (from the center for keyboard activation); dim applies the pressed opacity to the whole control and draws no state layer; none draws no answer to the press. Under ripple and dim only the container color stays with the state under the press; label, icon, opacity and shape still come from the pressed tokens. Under none every part stays with the state under the press. The ripple grows over comp.menubar.motion.feedback-duration with motion.state-easing, fades over motion.state-duration with motion.state-easing once the press has ended and press-hold has passed, and appears whole where motion is reduced.
- **MBR-8** THE menubar title SHALL ease its container corners by sys.shape.corner-smoothing (0 is a quarter circle, 0.6 the iOS continuous corner; a platform with only the OS curve draws it for any amount above 0) and show its keyboard focus as sys.behavior.focus-style names (ring or glow); a platform that cannot draw a choice SHALL fall back to the first value and state that in its README.
- **MBR-9** WHEN the user activates an enabled title whose menu is closed — by a press with a pointer, a tap, Enter, Space, Down Arrow or Up Arrow while the title has focus — THE menubar SHALL open that title's menu without delay, close any other open menu of the bar (MBR-10), set the menu's open to true and emit the menu's toggle once with true. The open menu SHALL be a Tanrei Menu anchored to the title, below it with the start edges aligned, comp.menu.surface.offset from it, flipping above and shifting along the title as MNU-2 says, drawn from the menu's own tokens and holding the menu's own item kinds (actions, link items, checkbox and radio items, groups, submenus, shortcuts), every one of which SHALL behave as the menu's spec says except where MBR-13 to MBR-15 say otherwise. Focus SHALL move into the menu as MNU-1 says — to its first enabled item, or to its last enabled item when the key was Up Arrow, and to its first or last item where none is enabled (MNU-43) — showing the focus ring only when the input was a key. WHILE its menu is open THE menubar SHALL draw the title in the expanded condition (MBR-3) in whatever interaction state it is in.
- **MBR-10** THE menubar SHALL show at most one of its menus at a time. WHEN a menu opens while another menu of the bar is open THE menubar SHALL close the other first, every submenu of it with it, set its open to false and emit its toggle once with false. WHEN the user presses the title of the open menu with a pointer or taps it THE menubar SHALL close that menu, set its open to false, emit its toggle once with false and keep focus on the title. WHEN the product sets a menu's open THE menubar SHALL open or close that menu as an activation would, without emitting that menu's toggle for the product's own change; IF the product sets open on more than one menu THE menubar SHALL show the first of them in the order given, and in debug builds report it.
- **MBR-11** WHILE a menu of the bar is open, WHEN a pointer that can hover moves onto another enabled title THE menubar SHALL open that title's menu at once, with no delay, and close the one that was open (MBR-10), moving focus into the new menu as MNU-1 says without showing a focus ring; a pointer on a disabled title, or on the bar between titles, SHALL leave the open menu open. WHILE no menu of the bar is open a pointer on a title SHALL only render it hovered and SHALL open nothing. Touch has no hover: a tap on another title opens its menu (MBR-9).
- **MBR-12** THE menubar SHALL be one Tab stop: the title that had keyboard focus last or whose menu was opened last, by any input, whichever came later, or else its first title. WHILE a title has keyboard focus and no menu is open, the arrow key that points to the inline end (Right Arrow in a left-to-right layout, Left Arrow in a right-to-left one) and the one that points to the inline start SHALL move focus to the next and the previous title, wrapping at the ends, Home and End SHALL move it to the first and the last title, and a printable character typed with no modifier but Shift SHALL move it to the next title after the focused one, wrapping, whose label begins with that character, compared without regard to letter case, and nowhere when no label does; none of these keys SHALL open a menu. A disabled title and the overflow item (MBR-21) SHALL be reached by these keys like any other title, so that a person hears every menu the bar has. Tab and Shift+Tab SHALL move focus out of the bar, to what follows and what precedes it. Beyond these keys and those of MBR-9 THE menubar SHALL handle no key while no menu is open, and SHALL NOT let a key it handles scroll or act on what is around the bar.
- **MBR-13** WHILE a menu of the bar is open and focus is inside it, at any level, WHEN the user presses the arrow key that points to the inline end on an item that is not a submenu item THE menubar SHALL close that menu and every submenu of it, open the menu of the next enabled title, wrapping at the ends and passing over disabled titles, and move focus to that menu's first enabled item with the focus ring shown; WHEN the user presses the arrow key that points to the inline start while focus is in the menu's own surface, not in a submenu, THE menubar SHALL do the same towards the previous enabled title. These two keys replace what MNU-51 says for a menu that stands alone; on a submenu item the inline-end key still opens its submenu (MNU-43), and in a submenu the inline-start key still closes that submenu alone (MNU-48). WHERE the bar has one enabled title only, these keys SHALL do nothing and SHALL NOT let the key scroll or act on what is behind the menu. Each menu closed and opened this way SHALL have its open set and its toggle emitted once (MBR-9, MBR-10).
- **MBR-14** WHEN the user presses Escape or the platform's back while a menu of the bar is open and no submenu of it is open THE menubar SHALL close that menu, set its open to false, emit its toggle once with false and return focus to its title, showing the focus ring when the input was a key, so that the arrow keys go on along the bar. WHEN the user presses Tab or Shift+Tab while a menu of the bar is open, at any level, THE menubar SHALL close it the same way and SHALL let focus move on out of the bar, to what follows the bar for Tab and to what precedes it for Shift+Tab, never to another title. WHEN the user presses outside every surface of the open menu and outside the bar, or focus leaves the bar and the open menu, THE menubar SHALL close the menu the same way and SHALL NOT take focus back. WHILE no menu is open THE menubar SHALL NOT handle Escape.
- **MBR-15** WHEN the user activates an item of an open menu that closes its menu (an action or a link item, at any level: MNU-6, MNU-54) THE menubar SHALL close the menu, every submenu with it, set its open to false, emit its toggle once with false after the item's own event, and return focus to the menu's title, unless the product moved focus elsewhere while handling the item's event, in which case THE menubar SHALL leave focus where the product put it. A checkbox or radio item activated with Space leaves its menu open, as MNU-6 says.
- **MBR-16** THE menubar SHALL add no event to an item of its menus and take none away: an item's click, a checkbox item's change, a group's change and a submenu item's toggle are emitted as the menu's spec says, by the item or the group. THE menubar SHALL NOT listen for a keyboard shortcut that an item shows, nor run an item when its shortcut is pressed: the menu draws the shortcut and exposes it (MNU-31), and binding the keys is the product's. THE menubar SHALL define no access key of its own — no underlined letter in a title, no key that moves focus to the bar from elsewhere — and SHALL leave a product free to add one by moving focus to a title or setting a menu's open.
- **MBR-17** WHERE a title's visual size is below the minimum target THE menubar SHALL extend its hit area on both axes to sys.target.touch for touch input and sys.target.pointer for fine pointers, without changing its visual size; a platform that cannot tell the input type SHALL use sys.target.touch. Between two neighbouring titles the hit areas SHALL meet at the middle of comp.menubar.bar.gap and SHALL never overlap; a title narrower than the target SHALL be given the room its target needs by moving its neighbours apart, not by overlapping them.
- **MBR-18** WHILE a menu's disabled is true THE menubar SHALL render its title's container, label and opacity from the disabled component tokens of the unselected condition, SHALL NOT open its menu by any input or by the product's open, SHALL close it if it is open (MBR-10), SHALL NOT emit its toggle for an activation, SHALL keep the title reachable by the keys of MBR-12, and SHALL expose the title as a menu item that opens a menu, with the disabled state.
- **MBR-19** THE menubar SHALL expose itself with the menubar role, named by label, with a horizontal orientation; each title as a menu item that opens a menu, named by its menu's label, with whether that menu is open, the disabled state where it has it, and its position among the bar's titles and their number; and each open menu as a menu named by its title, its items exposed as the menu's spec says (MNU-24). The overflow item SHALL be one such title, named by overflowLabel (MBR-22). WHERE a platform has no menubar role THE menubar SHALL expose a group named by label that holds, in order, one button for each title, each saying that it opens a menu and whether that menu is open, and SHALL say so in its README.
- **MBR-20** WHILE label is empty THE menubar SHALL still render and work, and in debug builds report that it has no accessible name; WHILE a menu's label is empty THE menubar SHALL still draw its title, as an empty container of the title's height and paddings, keep it reachable and operable, and in debug builds report that the title has no name. IF the menubar holds neither a menu nor a bar item THE menubar SHALL draw the bar with nothing on it, take no focus, and in debug builds report it. IF a menu holds no item THE menubar SHALL still draw its title and open its surface, empty, on an activation, SHALL keep focus on the title while that menu is open, SHALL answer the inline arrow keys on that title as MBR-13 says for a menu's own surface and Escape and Tab as MBR-14 says, and in debug builds report it; WHILE such a menu is folded into the overflow item (MBR-22) it SHALL be a submenu item that draws its row, takes focus and opens nothing, as MNU-52 says of a submenu with no item. IF it holds something that is neither a menu nor a bar item (MBR-32) THE menubar SHALL give it no title, no key and no place in the row, and in debug builds report it: a field, a control of the product's own or an entry that holds a state would take the keys the bar moves focus with and would not be a menu item.
- **MBR-21** IF the titles need more inline size than the row has THE menubar SHALL keep every title at its own size, SHALL NOT wrap the row onto a second line, scroll it, shrink it or cut a label, and SHALL fold menus out of the row from its end, as few as make the rest fit, into one overflow item drawn as the last title of the row: the glyph more_horiz of the system's icon set at comp.menubar.icon.size, in the icon color of its condition and state (comp.menubar.unselected.icon.color at rest, comp.menubar.expanded.icon.color while its menu is open), drawn through the icon helper with sys.icon.family.unselected, sys.icon.fill.unselected, sys.icon.weight and an optical size clamped between sys.icon.optical-size.min and sys.icon.optical-size.max, centered in a container at least comp.menubar.container.height wide and tall with the corners of MBR-2. IF the first title does not fit beside the overflow item THE menubar SHALL fold every menu, so that the row is the overflow item alone. WHILE every title fits THE menubar SHALL draw no overflow item. THE menubar SHALL decide again what fits, at once and without a motion, whenever its inline size, its menus, a label, the text size or the layout direction changes.
- **MBR-22** THE menubar SHALL treat the overflow item as a title in every respect — its conditions, states, target, keys and hover (MBR-3 to MBR-17) — and SHALL open from it a Tanrei Menu that lists the folded menus in the order given, each as a submenu item named by that menu's label and holding that menu's items unchanged, a disabled menu as a disabled submenu item; these SHALL behave as MNU-42 to MNU-52 say, and the level the fold adds SHALL NOT count towards the depth MNU-52 reports. WHEN a folded menu's submenu opens or closes THE menubar SHALL set that menu's open and emit its toggle once, as it does for a menu opened from its own title, so that open and toggle mean the same wherever the menu is shown. WHEN a change of MBR-21 folds or unfolds the menu that is open THE menubar SHALL close it first (MBR-10) and, if focus was inside it, move focus to the title it is now reached from: its own, or the overflow item. WHILE overflowLabel is empty and the product's words do not give it THE menubar SHALL still draw the overflow item and let it work, SHALL expose it without a name, and in debug builds report the missing word once.
- **MBR-23** THE menubar SHALL supply no word of its own: its name is label and each title is its menu's label, given on the instance; the overflow item's name is overflowLabel, read from the instance and, where that is empty, from the product's words under the key menubarOverflowLabel; the words of every item are the menu's own props. A word nobody gave SHALL NOT be replaced by one in any language.
- **MBR-24** THE menubar SHALL take its layout direction from where it is used — the direction of the nearest ancestor that sets one, and the platform's own where none does — and SHALL have no direction setting of its own; WHEN that direction changes while the menubar is shown THE menubar SHALL draw itself for the new direction at once, without a motion of its own, keeping its focus, the title its Tab stop stands on and which menu is open, the open menu placed again by the new direction (MNU-2) and what fits decided again (MBR-21).
- **MBR-25** WHERE the layout direction is right-to-left THE menubar SHALL lay out its titles from the right edge in the order given, fold menus from the left end of the row and draw the overflow item at the left end, open each menu below its title with their right edges aligned, and move focus along the bar with Left Arrow to the next title and Right Arrow to the previous one (MBR-12, MBR-13); the order of focus and of reading SHALL stay the order given. The overflow item's glyph SHALL be mirrored exactly when the system's icon set marks its name as mirrored, by the icon helper and not by the bar.
- **MBR-26** THE menubar SHALL lay out each title's label as text of its own direction, isolated from the text around it: it takes the base direction of its first strong character, or the layout direction where it has none, so that a left-to-right word keeps its own order in a right-to-left layout and reorders nothing beside it; THE menubar SHALL still place each title by the layout direction, not by the text's own.
- **MBR-27** WHILE the text size is enlarged THE menubar SHALL grow each title with its label — the container's height is a minimum, and its width follows the label — and the row with its titles, keeping comp.menubar.bar.gap, comp.menubar.bar.padding-inline, comp.menubar.bar.padding-block and comp.menubar.container.padding-inline as they are, and SHALL decide again what fits (MBR-21), so that at twice the text size in a window 320 wide every menu is still reached, from its title or through the overflow item, with nothing cut and no scrolling sideways.
- **MBR-28** WHERE the platform draws with a person's own forced colors (the web's forced-colors mode, and a platform's equivalent where it has one) THE menubar SHALL draw each title's label and the overflow item's glyph in the platform's button text color, a disabled title in its disabled text color, the focus ring in its highlight color, and SHALL mark the title whose menu is open, and a hovered or pressed title, by the platform's highlight colors or by an outline of sys.border.hairline or more around the title's container, never by a fill the platform may remove; it SHALL draw no fill for the bar.
- **MBR-29** WHEN the colors of a title change between states or conditions THE menubar SHALL animate them over comp.menubar.motion.state-duration with comp.menubar.motion.state-easing, and SHALL change them at once where motion is reduced. WHEN one menu of the bar takes the place of another (MBR-11, MBR-13) THE menubar SHALL remove the one and show the other at once, with neither the close nor the open motion of MNU-4, so that moving along the bar does not flicker; the menu that opens from a bar with no menu open, and the last one to close, SHALL move as MNU-4 says.
- **MBR-30** WHEN a menu is added to the bar, removed from it, reordered or given another label or disabled value while the bar is shown THE menubar SHALL lay the row out again at once, without a motion; a menu that is removed while open SHALL be closed without emitting its toggle; WHEN the title that holds focus or the Tab stop is removed THE menubar SHALL move it to the title that followed, or to the one before where none follows, and SHALL NOT let focus fall out of the bar while a title remains.
- **MBR-31** WHILE a menu of the bar is open THE menubar SHALL NOT trap focus, SHALL NOT make the rest of the screen inert and SHALL draw no scrim: its menus are operated overlays that are not modal (MNU-25), and the bar itself is part of the page, not an overlay. A press outside that closes a menu SHALL also reach what is under it where the menu's own platform form lets it (MNU-5).
- **MBR-32** THE menubar SHALL take two kinds of entry in its row, in the order given and mixed freely: a menu, whose title opens it (MBR-9), and a bar item, which acts by itself — an action that is run at once or, WHILE its href is not empty, a link that goes somewhere (MBR-35). THE menubar SHALL give a bar item its place in the row among the titles and SHALL treat it as a title in every respect but one, that it has no menu: it is drawn as MBR-2 draws a title, from its own label; it is in the unselected condition, or in the selected one while it is a link item that is current (MBR-38), and never in the expanded one (MBR-3); it takes a title's states, focus ring, press answer, corners and target (MBR-4 to MBR-8, MBR-17), its hit area meeting its neighbours' as theirs meet; it is counted with the titles wherever this spec orders, measures, folds or mirrors them or lays them out again (MBR-1, MBR-21, MBR-24 to MBR-27, MBR-30); and it is one of the stops of the bar's one Tab stop, reached by the inline arrow keys, Home, End and a typed character exactly as a title is, a disabled one included, and it is where the Tab stop stands when it had keyboard focus or was activated last (MBR-12). WHILE the bar holds both menus and bar items THE menubar SHALL tell a menu's title from a bar item at rest by the indicator MBR-47 draws after each menu's title, and assistive technology by what MBR-42 says; WHILE every entry is a menu it SHALL draw none, the titles needing nothing to be told from each other.
- **MBR-33** WHEN the user activates an enabled bar item that is not a link item — by a press with a pointer, a tap, Enter or Space while it has focus, or the default action of assistive technology — THE menubar SHALL first close the menu of the bar that is open, if one is, as MBR-10 says, and SHALL then emit the bar item's click exactly once; it SHALL open nothing, and SHALL keep focus on the bar item, moved there without a focus ring when the input was a pointer or a touch, unless the product moved focus elsewhere while handling click, in which case it SHALL leave focus where the product put it. THE menubar SHALL activate a bar item for nothing else: not for focus arriving on it, not for a pointer over it, and not for the arrow keys, Home, End or a typed character that reach it, so that moving along the bar runs no command.
- **MBR-34** WHILE a bar item has keyboard focus THE menubar SHALL do nothing for Down Arrow and Up Arrow, which open a menu from a title and have none to open here, and SHALL NOT let them scroll or act on what is around the bar, so that the same two keys never open a menu on one entry of the row and move the page on the next; it SHALL NOT handle Escape (MBR-14), and Tab and Shift+Tab SHALL leave the bar as MBR-12 says.
- **MBR-35** WHILE a bar item's href is not empty THE menubar SHALL make it a link item, as MNU-53 makes an item of a menu one: the platform's own link to href (the web's anchor element; SwiftUI's Link; on Compose, Flutter and React Native an element with the platform's link semantics whose address is opened by the platform's opener), as BTN-22 says for a link button, so that whatever the platform gives a link is the platform's, and not the bar's to draw or to take over. WHERE the platform has a menubar role THE menubar SHALL expose a link item with the menu item role, on the link itself, and not with the link role, for the reason MNU-53 gives for a menu: the bar's role, an entry's position in it and its keys hold only while everything in the row is a menu item. THE menubar SHALL draw a link item exactly as it draws an action, from the same tokens in every state, with no look of its own for a link and none for a destination already visited, SHALL give the bar item's whole container and its hit area (MBR-17) to the link, and SHALL keep it one stop of the bar's Tab stop like any entry, never a Tab stop of its own.
- **MBR-36** WHEN the user activates an enabled link item as an entry of the bar is activated — by a click with the primary button and no modifier key, a touch, Enter or Space with no modifier key, or the default action of assistive technology — THE menubar SHALL close the menu of the bar that is open, if one is (MBR-10), emit the bar item's click exactly once, and then open href where target names, unless the product cancelled that click, in which case it SHALL open nothing: the product's own router has taken the navigation, as MNU-54 says of a menu's link item. It SHALL show the pressed state as MBR-6 and MBR-7 say and SHALL NOT hold the navigation back for sys.motion.duration.press-hold. Space SHALL activate a link item exactly as Enter does and SHALL scroll nothing, as MNU-54 says and for its reasons: a link item is exposed and operated as a menu item, nothing in its look tells it from the action beside it, and Space activates every other entry of the row. For every other activation the platform gives a link — on the web a click or Enter with a modifier key, a middle click and the link's context menu, on Apple platforms a long press that previews — THE menubar SHALL leave the link to the platform, SHALL prevent, replace or imitate none of it, and SHALL close no menu for it.
- **MBR-37** WHILE a bar item is a link item and its target is new THE menubar SHALL open href in a new context, as BTN-24 says for a link button (on the web a new tab or window that is given no handle to the page that opened it), and SHALL draw the glyph open_in_new of the system's icon set after the label, comp.menubar.container.gap from it and inside the container's paddings, at comp.menubar.icon.size, in the icon color of the bar item's state (comp.menubar.unselected.icon.color at rest), through the icon helper as MBR-21 draws the overflow item's glyph — the helper mirrors it in a right-to-left layout because the icon set marks its name — and hidden from assistive technology; the bar item SHALL then be as wide as its label, the gap and the glyph need. THE menubar SHALL expose targetLabel as the bar item's description — read from the bar item and, where that is empty, from the product's words under the key targetLabel — and WHILE neither gives it SHALL still render and in debug builds report that a link that opens a new context does not say so. WHILE target is same THE menubar SHALL draw no mark and SHALL ignore targetLabel.
- **MBR-38** WHILE a link item's current is true THE menubar SHALL expose it as the current item of its set (on the web the current page; on a platform without that state, the selected state), SHALL keep it a link that takes focus and can be followed, and SHALL draw it from the selected condition (MBR-3): its container in comp.menubar.selected.container.color, which is the fill of the menu's row the person is on (comp.menu.current.container.color), in every contrast scheme, and its label and mark in that condition's colors, in every state, at its label's own weight, so that the place the person is on is drawn in the bar as a menu draws it (MNU-58). It is never mistaken for the title of an open menu: the expanded condition has colors of its own, and the current page is a fact about where the person is, not a menu that is shown. THE menubar SHALL NOT set current itself on any activation: where the product is, is the product's to say (NVB-31). IF more than one bar item is current THE menubar SHALL draw and expose each as given and in debug builds report it; WHILE a bar item's href is empty THE menubar SHALL ignore its current and in debug builds report it.
- **MBR-39** WHILE a bar item's disabled is true THE menubar SHALL render its container, label, mark and opacity from the disabled component tokens of the unselected condition, SHALL NOT emit its click or act on any input, SHALL keep it reachable by the keys of MBR-12 as MBR-18 keeps a disabled title, and SHALL expose it with the disabled state; a disabled link item SHALL NOT be a link that can be followed, as MNU-56 says of a menu's: it SHALL keep the exposure MBR-35 gives it, with the disabled state and no destination, and SHALL open nothing by any means the platform gives a link (on the web the anchor carries no href, so there is no context menu entry, no drag and no new tab for it).
- **MBR-40** WHEN an inline arrow key of MBR-13 is pressed in an open menu and the next enabled entry in that direction — wrapping at the ends, and passing over disabled bar items as it passes over disabled titles — is a bar item THE menubar SHALL close the open menu and every submenu of it, set its open to false and emit its toggle once with false, and SHALL move focus to that bar item with the focus ring shown; it SHALL open nothing and SHALL NOT activate the bar item. No menu is then open, so the keys that follow are those of MBR-12 and MBR-34 and open nothing: THE menubar SHALL keep no memory that a menu was open, and moving on from the bar item SHALL NOT open the next title's menu — a menu follows focus along the bar only while a menu is shown (MBR-11, MBR-13). WHERE the open menu's title is the bar's only enabled entry these keys SHALL do nothing, as MBR-13 says.
- **MBR-41** WHILE a menu of the bar is open, WHEN a pointer that can hover moves onto a bar item THE menubar SHALL render the bar item hovered and SHALL leave the open menu open and focus where it is, as MBR-11 says of a disabled title: a bar item has no menu to show in the other's place, and a menu that closed under a pointer on its way along the row would have to be opened again with a press at the next title. A press on the bar item then activates it (MBR-33, MBR-36), which closes the open menu first. WHILE no menu of the bar is open a pointer on a bar item SHALL only render it hovered.
- **MBR-42** THE menubar SHALL expose each bar item as a menu item named by its label, which SHALL NOT say that it opens a menu and SHALL carry no expanded state (on the web neither aria-haspopup nor aria-expanded, in any value), with the disabled state where it has it and with its position among the bar's entries and their number, the titles, the bar items and the overflow item counted together in the order drawn; a link item as MBR-35 says, with its description where it opens a new context (MBR-37) and with whether it is current (MBR-38). WHERE a platform has no menubar role and exposes the group of MBR-19 instead THE menubar SHALL put in that group, in the order given among the titles' buttons, a button for an action and, for a link item, the platform's link with its link role or trait in place of the button's.
- **MBR-43** WHEN MBR-21 folds entries out of the row THE menubar SHALL fold bar items as it folds menus — whole, from the end, in the order given, whatever their kind — and SHALL list a folded bar item in the overflow item's menu (MBR-22) at its place in that order among the folded menus' submenu items, not as a submenu but as an item of that menu: an action as the menu's own item (MNU-6) and a link item as the menu's own link item, with the same href, target and targetLabel (MNU-53 to MNU-56), each named by the bar item's label and disabled while the bar item is. WHEN the user activates a folded bar item THE menubar SHALL emit the bar item's own click exactly once — the same event of the same bar item, which a product cancels for a link item as MBR-36 says — so that click means the same wherever the bar item is shown, and SHALL then close the overflow item's menu and return focus to the overflow item as MBR-15 says, unless the product moved focus elsewhere while handling click, a link item opening its destination after that; the activations MNU-54 leaves to the platform SHALL leave the overflow item's menu open. The click comes before the closing here and after it in the row (MBR-33, MBR-36), and each is the order its place already has: in the row the menu that is open is another entry's, and an entry of the row that is pressed has the other's menu closed before it answers, as a pressed title does (MBR-10); in the fold the bar item is an item of the menu that is open, and an item's own event comes before its menu closes (MNU-6, MBR-15). In both places THE menubar SHALL emit click before it settles where focus rests, so that focus the product moved while handling click is left where the product put it. A folded link item whose target is new SHALL be marked and described as the menu marks and describes its own (MNU-55), and a folded link item that is current SHALL be the menu's own current link item (MNU-58): exposed as current, and filled as the menu fills the row the person is on (MBR-38). THE menubar SHALL keep the overflow item a title that opens a menu, whatever is folded into it, so that it never acts by itself: WHERE everything folded is bar items its menu holds items and no submenu, and WHERE the row is the overflow item alone the bar is that one menu.
- **MBR-44** WHEN a bar item's target names a value the menubar does not define THE menubar SHALL treat it as same, and in debug builds report the unknown value. IF a bar item's href is only white space, or names a script to run rather than a place to go (the web's javascript: scheme), or cannot be read as an address by the platform, THE menubar SHALL make the bar item an action without a destination, and in the last two cases report it in debug builds, as BTN-26 says for a button. WHILE a bar item's href is empty THE menubar SHALL ignore its target and targetLabel. WHILE a bar item's label is empty THE menubar SHALL still draw it as an empty container of a title's height and paddings, keep it reachable and operable, and in debug builds report that it has no name, as MBR-20 says of a title. THE menubar SHALL give a destination to a bar item alone: WHERE a platform lets one be written on a menu THE menubar SHALL ignore it, keep the menu what it is, and in debug builds report it. THE menubar SHALL take no entry that holds a state: a checkbox or a radio entry directly in the row is refused as MBR-20 says, because a choice that is switched needs a mark a title has no place for, and it belongs in a menu of the bar, where the menu's checkbox and radio items mark it. IF the menubar holds bar items and no menu THE menubar SHALL still render and work, and in debug builds report it: a row of actions alone is a toolbar, and a row of links alone is navigation.
- **MBR-45** WHERE the platform shows the product's own markup before the component runs (the web, before its elements are defined and where scripting is off) THE menubar SHALL leave every link item a link that works: its anchor is the product's own element in the document, shown in the bar's place in the order given and followed by the browser as any link is, with no menubar role, no menu item role and no roving focus on anything until the bar runs. WHEN the bar begins to run THE menubar SHALL take those anchors as its link items where they stand, SHALL add to them the role and the focus order MBR-35 and MBR-12 give, and SHALL NOT copy, move or replace them; a link item that is folded (MBR-43) SHALL keep its anchor in the document, not displayed. A menu and an action SHALL show nothing there: their words are the bar's to draw and their work is the product's script.
- **MBR-46** WHERE the platform draws with a person's own forced colors (the web's forced-colors mode, and a platform's equivalent where it has one) THE menubar SHALL draw an action and its states as MBR-28 draws a title, and a link item's label and mark in the platform's link color, a disabled one in its disabled text color: the colors are then the person's and not the design system's, and what they chose for a link holds for a link in a bar as it does anywhere. A current link item, whose fill the mode removes, SHALL be marked by a line of sys.border.thick inside its container's edge in the platform's link color.
- **MBR-47** WHILE the menubar holds at least one bar item and at least one menu THE menubar SHALL end the title of each menu (not a bar item's, and not the overflow item, which is a glyph of its own, MBR-21) with the glyph expand_more of the system's icon set, comp.menubar.container.gap after its label and inside the container's paddings, at comp.menubar.indicator.size, in the icon color of the title's condition and state (comp.menubar.unselected.icon.color at rest, comp.menubar.expanded.icon.color while its menu is open), drawn through the icon helper with sys.icon.family.unselected, sys.icon.fill.unselected, sys.icon.weight and an optical size clamped between sys.icon.optical-size.min and sys.icon.optical-size.max, never mirrored and not turned while the menu is open, and hidden from assistive technology, so that a person sees before pressing which entries open a menu and which act at once; the title SHALL then be as wide as its label, the gap and the glyph need, and MBR-21 SHALL measure it so. WHILE every entry of the bar is a menu THE menubar SHALL draw no indicator. Whether the bar mixes the two kinds SHALL be decided from all its entries, folded or not, so that folding never adds or takes away an indicator; WHEN entries are added or removed so that this changes THE menubar SHALL draw or remove the indicators at once, without a motion, and decide again what fits (MBR-21, MBR-30). A menu folded into the overflow item is its submenu item and draws that item's indicator (MNU-46), not this one. IF the icon set cannot draw the glyph yet THE menubar SHALL draw nothing in its place, never its name, and keep its room.
- **MBR-48** WHERE the platform has ARIA attributes (the web), the menubar's host and an action bar item's host carries its role (MBR-19, MBR-42) itself, so what the product writes on it is not moved, but for a name: WHILE label is not empty THE menubar SHALL hold the product's aria-label and aria-labelledby on that host as their data-aria- twins, so that label is its whole name although the platform gives aria-labelledby the precedence, and WHEN label is emptied SHALL give them back as they were written; WHILE label is empty a name the product gives so — aria-label, or aria-labelledby naming an element — SHALL be its name and SHALL NOT be reported as having none in debug builds (MBR-20, MBR-44). WHILE a bar item is folded into the overflow item, or holds the product's own anchor (MBR-35), its host is nothing, and THE menubar SHALL hold them as well, giving them back when the item is an action in the row again. WHEN the product removes one, or its data-aria- twin, or sets the ARIA property that reflects it (ariaLabel, ariaLabelledByElements) to null, THE menubar SHALL take it away.

### Tokens

As written in the token documents (DTCG): an alias in braces names the token it takes its value from, which each design system resolves. On the web each token is a CSS custom property: `--tanrei` and the name after `tanrei`, joined by hyphens (`tanrei.comp.menubar.…` → `--tanrei-comp-menubar-…`).

#### `tanrei.comp.menubar`

| Token | Type | Value |
| --- | --- | --- |
| `comp.menubar.bar.color` | `color` | `{"colorSpace":"srgb","components":[0,0,0],"alpha":0,"hex":"#000000"}` |
| `comp.menubar.bar.padding-inline` | `dimension` | `{tanrei.sys.space.space50}` |
| `comp.menubar.bar.padding-block` | `dimension` | `{tanrei.sys.space.space50}` |
| `comp.menubar.bar.gap` | `dimension` | `{tanrei.sys.space.space25}` |
| `comp.menubar.container.height` | `dimension` | `40px` |
| `comp.menubar.container.padding-inline` | `dimension` | `{tanrei.sys.space.space150}` |
| `comp.menubar.container.gap` | `dimension` | `{tanrei.sys.space.space50}` |
| `comp.menubar.container.shape` | `dimension` | `{tanrei.sys.shape.corner.small}` |
| `comp.menubar.label.typescale` | `typography` | `{tanrei.sys.typescale.label}` |
| `comp.menubar.icon.size` | `dimension` | `{tanrei.sys.icon.medium}` |
| `comp.menubar.indicator.size` | `dimension` | `{tanrei.sys.icon.small}` |
| `comp.menubar.unselected.container.color` | `color` | `{"colorSpace":"srgb","components":[0,0,0],"alpha":0,"hex":"#000000"}` |
| `comp.menubar.unselected.label.color` | `color` | `{tanrei.sys.color.on-surface}` |
| `comp.menubar.unselected.icon.color` | `color` | `{tanrei.sys.color.on-surface}` |
| `comp.menubar.unselected.state-layer.color` | `color` | `{tanrei.comp.menubar.unselected.label.color}` |
| `comp.menubar.selected.container.color` | `color` | `{tanrei.comp.menu.current.container.color}` |
| `comp.menubar.selected.label.color` | `color` | `{tanrei.comp.menu.current.label.color}` |
| `comp.menubar.selected.icon.color` | `color` | `{tanrei.comp.menu.current.leading-icon.color}` |
| `comp.menubar.selected.state-layer.color` | `color` | `{tanrei.comp.menubar.selected.label.color}` |
| `comp.menubar.expanded.container.color` | `color` | `{tanrei.sys.color.surface-container-high}` |
| `comp.menubar.expanded.label.color` | `color` | `{tanrei.sys.color.on-surface}` |
| `comp.menubar.expanded.icon.color` | `color` | `{tanrei.sys.color.on-surface}` |
| `comp.menubar.expanded.state-layer.color` | `color` | `{tanrei.comp.menubar.expanded.label.color}` |
| `comp.menubar.motion.state-duration` | `duration` | `{tanrei.sys.motion.role.state.default}` |
| `comp.menubar.motion.state-easing` | `cubicBezier` | `{tanrei.sys.motion.easing.state}` |
| `comp.menubar.motion.feedback-duration` | `duration` | `{tanrei.sys.motion.role.feedback}` |

Per-state tokens, valued by the design system's pattern rules (not written by hand):

- `comp.menubar.<variant>.<state>.<property>` for the variants `unselected`, `selected`, `expanded`, the states `hovered`, `focused`, `pressed`, `disabled` and the properties `container.color`, `label.color`, `icon.color`, `state-layer.color`.
- `comp.menubar.<state>.<property>` for the states `hovered`, `focused`, `pressed`, `disabled` and the properties `opacity`, `container.shape`.

## Guidelines

### Menus first, and what else the row takes

A title opens a menu, and most of a bar is titles. An entry that acts by itself is the exception: one or two beside the menus, for the reasons under [Entries that act](https://tanrei.chnotchy.com/components/menubar/#entries-that-act). A product with many commands that should be one press away has a toolbar or an app bar for them.

The row takes menus and bar items, and nothing else. A Button, an anchor written straight into the bar, a field or a checkbox would take the keys the bar moves focus with, and would not be a menu item. It is given no place in the row and is reported in debug builds.

### Moving along the bar runs nothing

Focus arriving on a bar item, the arrow keys, Home, End, a typed letter and a pointer passing over it never activate it. Only a press, Enter or Space does. Down Arrow and Up Arrow on a bar item do nothing, and do not scroll the page: the same keys must not open a menu on one entry and move the page on the next.

From inside a menu, the arrow key along the row goes on to the next entry. If that is a title, its menu opens. If it is a bar item, the open menu closes and focus lands on the bar item. Nothing opens and nothing runs, and from there the arrow keys move along the row without opening menus until you open one again.

### The pointer

A press on a title opens its menu. A press on the open title closes it. While one menu is open, a pointer that moves onto another title opens that one at once, without a delay and without a motion. While none is open, hovering only hovers: the bar opens nothing a person did not ask for.

A pointer that moves onto a bar item while a menu is open only hovers it. The open menu stays, so a pointer travelling from File to View across Run does not lose the menu on the way. A press on the bar item closes the menu and then activates it.

### After a command

When an item is activated, its menu closes and focus returns to the menu’s title. A command that acts on a document usually wants focus back in the document. Move it in your handler, and the bar leaves it where you put it.

### Shortcuts and access keys

A menu draws an item’s shortcut and exposes it to assistive technology. Neither the menu nor the bar listens for the keys. You bind them, because only the product knows which shortcuts apply where focus is.

The bar has no access keys: no underlined letter in a title, and no key that jumps to the bar. They differ by platform, collide with the browser’s own on the web, and the letter is chosen per language. Once focus is on the bar, typing a letter moves to the next title that begins with it. To give a key of your own, set a menu’s `open` or move focus to a title.

### A narrow window

Titles keep their size and are never cut. When the row has no room for all of them, the bar folds entries whole from the end, as few as it must, into one overflow item drawn as the icon set’s `more_horiz`. Its menu holds each folded menu as a submenu with the same label and the same items, and each folded bar item as an item: an action as a menu item, a link item as a link item with the same address. When nothing fits, the row is that one item. The overflow item always opens a menu and never acts by itself.

The keys, the roles and the order are the same at every width, and no command is lost. A folded menu’s `open` and `toggle` mean what they mean in the row. A folded bar item’s `click` is the same event on the same element: your listener on the bar item, or on your anchor, hears it once wherever the entry is shown. Folded, it hears it while the overflow item’s menu is still open, and the menu closes after. Give the overflow item a name with `overflow-label`, or once for the product with `setWords({ menubarOverflowLabel: … })`.

Whether to show a menubar at all on a phone is yours to decide. There, commands in an app bar’s actions and its “more” menu are the idiom, and a product is right not to render the bar. The fold exists so that a bar which is rendered never loses a command.

### Where the platform has a menu bar of its own

A desktop system’s bar outside the window, and a tablet’s bar for a hardware keyboard, are drawn by the system from commands the product declares. Give your commands to that bar as well, with the platform’s own API: people look for them there. Tanrei’s menubar is the one inside your window, drawn from Tanrei’s tokens. It does not fill or replace the system’s.

### Do

- Use it for an application’s commands, when there are enough of them to need several named menus.
- Name each menu with one or two words that say what its commands act on.
- Keep a menu in the bar when none of its commands apply, and disable it. A person still hears that it exists.
- Show each command’s shortcut in its item, and bind the keys yourself.
- Move focus to what a command acts on when it has run.

### Don’t

- Don’t use it for a site’s sections or pages.
- Don’t put a Button, a bare link, a toggle or a field in the row. An action or a link goes in as a bar item.
- Don’t make a bar of bar items alone, and don’t put a command that cannot be undone on the bar.
- Don’t open a menu when a pointer merely passes over a title.
- Don’t mark a title as selected. The open title is marked only while its menu is shown.
- Don’t restyle a bar’s menus apart from the product’s other menus. They are Menus, and take the menu’s tokens.

## Accessibility

### What the component handles

- The bar is exposed with the menubar role, named by `label`, horizontal. Each title is a menu item that opens a menu, named by its menu’s label, with whether that menu is open, whether it is disabled, and its position among the entries. An open menu is a menu named by its title.
- A bar item is a menu item named by its label. It does not say that it opens a menu and has no expanded state. A link item is your anchor with the menu item role, not the link role: assistive technology reads a menubar item by item, and the menubar role is valid only while every entry is a menu item. It says its `target-label` as its description and whether it is the current page.
- The whole bar is one stop in the focus order: the entry focused or activated last or whose menu was opened last, or else the first. A link item is never a Tab stop of its own.
- On a title or a bar item: the arrow keys along the row move to the next and previous entry and wrap; Home and End move to the first and last; a typed character moves to the next entry that begins with it. None of these opens a menu or runs anything. On a title, Enter, Space and Down Arrow open the menu with focus on its first enabled item; Up Arrow opens it with focus on its last enabled item. On a bar item, Enter and Space activate it, and Down Arrow and Up Arrow do nothing.
- In a menu: the menu’s own keys. The arrow key toward the end of the row opens a submenu on a submenu item and, on any other item at any depth, goes on to the next enabled entry: a title’s menu opens, and a bar item takes focus. The arrow key toward the start closes a submenu, and in the menu’s own surface goes to the previous entry. Escape closes the innermost open submenu. With no submenu open, it closes the menu and returns focus to its title. Tab closes the menu and leaves the bar.
- Disabled titles are reached along the bar, so that a screen reader says the menu exists and is unavailable. With a menu open the same keys pass over them.
- Keyboard focus shows the focus ring around the title. Focus gained by a pointer does not.
- A title’s hit area reaches the minimum target without changing what is drawn. A title narrower than the target keeps the target’s length in the row.
- An open menu is not modal. Focus is not trapped, nothing is made inert, and a press outside also reaches what is under it.
- In a right-to-left layout the titles run from the right, the row folds at the left end, each menu opens with its right edge on its title’s, and Left Arrow is “next”. A title’s label keeps its own direction.
- With enlarged text each title grows with its label and the row folds what no longer fits. At a width of 320 with text at 200% every menu is still reached and nothing scrolls sideways.
- In forced colors the labels take the button text color, the open title the highlight colors, and a hovered title a line around it. A link item takes the link color a person chose, and a disabled entry the disabled text color. The current link item, whose fill forced colors remove, gets a line inside its edge in the link color.
- A bar, a menu or a bar item without a label, a menu without items, anything in the bar that is neither a menu nor a bar item, a bar of bar items alone, a link item that opens a new tab without saying so, and an overflow item without a name are reported in debug builds.

### What you need to do

- Give the bar a `label` in the language of the page (“Application menu”). It is never drawn.
- Give every menu a `label`, every action a `label`, and every link item’s anchor its text.
- Give a link item that opens a new tab a `target-label`, and set `aria-current="page"` on the link item for the page a person is on.
- Give the overflow item a name with `overflow-label` or with the product’s words. The component supplies no words.
- Bind the shortcuts your items show.
- Where the system has a menu bar of its own, declare your commands to it as well.
- Do not use a menubar for navigation.
