menubar

Keyboard-first top-level navigation with open/close menu behavior.

Use ng-menubar around a strip of menu groups. Menu triggers support:

  • ArrowLeft/ArrowRight to move between menus
  • Enter/Space/ArrowDown to open a menu
  • Escape to close menus
  • Home/End shortcuts when a trigger is focused
<nav ng-menubar aria-label="Application menu">
  <section>
    <button>File</button>
    <menu>
      <button>New</button>
      <button>Open</button>
    </menu>
  </section>
  <section>
    <button>Edit</button>
  </section>
</nav>

Example

View source
<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>AngularCSS Menubar</title>
    <link rel="stylesheet" href="../../css/preflight.css" />
    <link rel="stylesheet" href="../../css/angular.css" />
    <link rel="stylesheet" href="../example.css" />
    <script src="../../js/angular-ts.umd.js"></script>
    <script src="../../js/angular-css.umd.js"></script>
  </head>
  <body
    ng-app="angular.css"
    ng-cloak
    ng-init="menubarDemo={bookmarks:false,fullUrls:true,profile:'benoit'}"
    data-example="menubar-demo"
  >
    <main class="visual-example">
      <nav ng-menubar aria-label="Browser application menu">
        <section>
          <button type="button">File</button>
          <menu>
            <section>
              <button type="button">New Tab <kbd>⌘T</kbd></button>
              <button type="button">New Window <kbd>⌘N</kbd></button>
              <button type="button" disabled>New Incognito Window</button>
            </section>
            <hr />
            <section>
              <details>
                <summary>Share</summary>
                <menu>
                  <section>
                    <button type="button">Email link</button>
                    <button type="button">Messages</button>
                    <button type="button">Notes</button>
                  </section>
                </menu>
              </details>
            </section>
            <hr />
            <section>
              <button type="button">Print... <kbd>⌘P</kbd></button>
            </section>
          </menu>
        </section>

        <section>
          <button type="button">Edit</button>
          <menu>
            <section>
              <button type="button">Undo <kbd>⌘Z</kbd></button>
              <button type="button">Redo <kbd>⇧⌘Z</kbd></button>
            </section>
            <hr />
            <section>
              <details>
                <summary>Find</summary>
                <menu>
                  <button type="button">Search the web</button>
                  <hr />
                  <button type="button">Find...</button>
                  <button type="button">Find Next</button>
                  <button type="button">Find Previous</button>
                </menu>
              </details>
            </section>
            <hr />
            <section>
              <button type="button">Cut</button>
              <button type="button">Copy</button>
              <button type="button">Paste</button>
            </section>
          </menu>
        </section>

        <section>
          <button type="button">View</button>
          <menu>
            <section>
              <button
                type="button"
                aria-checked="{{ menubarDemo.bookmarks }}"
                ng-click="menubarDemo.bookmarks=!menubarDemo.bookmarks"
              >
                Bookmarks Bar
              </button>
              <button
                type="button"
                aria-checked="{{ menubarDemo.fullUrls }}"
                ng-click="menubarDemo.fullUrls=!menubarDemo.fullUrls"
              >
                Full URLs
              </button>
            </section>
            <hr />
            <section>
              <button type="button" inset>Reload <kbd>⌘R</kbd></button>
              <button type="button" inset disabled>
                Force Reload <kbd>⇧⌘R</kbd>
              </button>
            </section>
            <hr />
            <button type="button" inset>Toggle Fullscreen</button>
            <hr />
            <button type="button" inset>Hide Sidebar</button>
          </menu>
        </section>

        <section>
          <button type="button">Profiles</button>
          <menu>
            <fieldset aria-label="Active profile">
              <button
                type="button"
                aria-checked="{{ menubarDemo.profile === 'andy' }}"
                ng-click="menubarDemo.profile='andy'"
              >
                Andy
              </button>
              <button
                type="button"
                aria-checked="{{ menubarDemo.profile === 'benoit' }}"
                ng-click="menubarDemo.profile='benoit'"
              >
                Benoit
              </button>
              <button
                type="button"
                aria-checked="{{ menubarDemo.profile === 'luis' }}"
                ng-click="menubarDemo.profile='luis'"
              >
                Luis
              </button>
            </fieldset>
            <hr />
            <button type="button" inset>Edit...</button>
            <hr />
            <button type="button" inset>Add Profile...</button>
          </menu>
        </section>
      </nav>
    </main>
  </body>
</html>

Installation

Install AngularCSS, load its stylesheet, and include the angular.css module in your AngularTS application. See Installation for the complete setup.

This component’s root directive is [ng-menubar]. Importing the package registers it with the AngularCSS angular.css module; there is no per-component JavaScript registration step.

Anatomy

Directive selectors

  • ng-menubar

Semantic structure

Each top-level section requires one native button trigger and one menu. The root directive inspects semantic sections, fieldsets, buttons, separators, keyboard hints, and nested details; no child directives or anatomy classes are required.

API

Attributes and state

AttributeAccessPurpose
aria-checkedInput/outputARIA relationship or state.
aria-controlsOutputID of the element controlled by a trigger.
aria-expandedOutputOpen or expanded state exposed to assistive technology.
aria-haspopupOutputType of popup controlled by the trigger.
aria-hiddenOutputWhether generated or collapsed content is hidden from assistive technology.
aria-labelledbyOutputID of the element that supplies the accessible name.
dirInputText and interaction direction: ltr or rtl.
openInputInitial or controlled open state.
roleOutputExplicit semantic role when native HTML does not provide one.
tabindexInput/outputKeyboard focus order for composite descendants.

Input attributes are read from authored HTML. Output attributes are maintained by AngularCSS for CSS and testing. Input/output attributes may be authored for a controlled initial state and are then synchronized by the directive.

CSS custom properties

This directive does not write component-specific CSS custom properties.

DOM events

This component does not emit a component-specific custom event.

Native DOM events continue to work normally. AngularTS event directives such as ng-click and ng-keydown, plus the data-change model callback, remain application-owned.

Behavior

The directive owns top-level roving focus, menu and submenu disclosure, enabled-item navigation, Escape and outside-click closure, DOM-order synchronization for dynamically inserted menus, and direction-aware horizontal keys. AngularTS remains responsible for command execution, checkbox and radio values, and structural content such as ng-if.

AngularCSS does not replace AngularTS interpolation, bindings, structural directives, form controllers, validation, or application state.

Accessibility

The root exposes role="menubar" and keeps one enabled top-level trigger in the tab order. Triggers identify their menus with aria-controls; disabled triggers and items are skipped. Arrow keys follow visual direction, submenu keys remain local to the submenu, and Escape restores focus to the active trigger.

Authored accessible names and relationships are preserved. Test the final composition with keyboard navigation and assistive technology because labels and content come from the application.

Customization

Target [ng-menubar], semantic descendants, component classes, and generated state with ordinary CSS. Keep behavior and accessible state in the TypeScript directive; visual choices belong in the application stylesheet.

Read Customization for layer order, design tokens, state variants, and iframe demo isolation.