# Navbar

> Material Design 3 top app bars, from the HTML.

## Anatomy

The bar is the markup. A `<header>` whose child is a `<nav>` is a top app bar. The heading is the headline. Icon-only links and buttons are the leading and trailing actions. A `<menu>` (or `<ul>`) holds text destinations. There is no `navbar`, `nav-wrapper`, or `brand-logo` class. Switching between app views at the bottom of the screen is a [navigation bar](/navigation-bar.html.md).

Tokens follow the [M3 app bar spec](https://m3.material.io/components/app-bars/specs). The container is `surface` at rest, the headline is `on-surface` at `title-large`, and icons are 24dp in a 48dp target, inset 4dp. Icons inherit the header color so a fill + `on-*` pair stays readable. The small bar is 64dp tall. Pair a fill utility with its `on-*` text class if you want a colored bar.

The bar is CSS for layout. `AppBar` collapses `header.medium` and `header.large` on scroll, and opens the related search view when a search field in the bar is selected. Menus and the navigation drawer are separate components that `AutoInit()` starts. A `navigation-drawer-trigger` inside the bar is still required — that class is the NavigationDrawer contract, not bar chrome. Tabs live in their own bar — do not nest `.tabs` in the header.

### Small

Default. Leading icon, headline, trailing actions. DOM order is the layout — the headline grows, so anything after it sits on the end.

## Title

```
<header>
  <nav aria-label="Main">
    <button type="button" aria-label="Menu">
      <span class="material-symbols" aria-hidden="true">menu</span>
    </button>
    <h2>Title</h2>
    <a href="#!" aria-label="Search"><span class="material-symbols" aria-hidden="true">search</span></a>
    <a href="#!" aria-label="More"><span class="material-symbols" aria-hidden="true">more_vert</span></a>
  </nav>
</header>
```

## Destinations

Text links go in a `<menu>`. Put the menu after the heading to align it on the end; put it first to align it on the start. Hide it below the Expanded breakpoint and pair it with a navigation drawer trigger when the bar has to collapse.

## Title

-   Sass
-   Components
-   JavaScript

```
<header>
  <nav aria-label="Main">
    <h2>Title</h2>
    <menu>
      <li><a href="#!">Sass</a></li>
      <li><a href="#!">Components</a></li>
      <li><a class="active" href="#!">JavaScript</a></li>
    </menu>
  </nav>
</header>
```

`active` goes on the link, not the list item. The state layer mixes `currentColor` at 8% hover and 10% active, so it follows the theme and any fill you put on the header.

## Center-aligned

Add `center` to the header. The headline is taken out of flow so the leading and trailing actions can sit on the edges without shifting it. Keep the title short enough that it does not run under the icons.

## Title

```
<header class="center">
  <nav aria-label="Main">
    <button type="button" aria-label="Back">
      <span class="material-symbols" aria-hidden="true">arrow_back</span>
    </button>
    <h2>Title</h2>
    <a href="#!" aria-label="More"><span class="material-symbols" aria-hidden="true">more_vert</span></a>
  </nav>
</header>
```

## Medium and large flexible

Same markup as the small bar. `medium` is the Expressive medium-flexible bar: 112dp with a `headline-medium` title on the second row. `large` is large-flexible: 120dp with `display-small`. The deprecated medium/large bars used `headline-small` / 152dp; do not recreate those. The title wraps to two lines. It is `order`ed onto the bottom row so the first row can hold the leading icon on the start and the trailing icons on the end. Add `center` as well to center that second-row title. On scroll, `AppBar` adds `collapsed` and the bar is the small 64dp row.

## Medium title

## Large title

```
<header class="medium">
  <nav aria-label="Main">
    <button type="button" aria-label="Back">
      <span class="material-symbols" aria-hidden="true">arrow_back</span>
    </button>
    <h2>Medium title</h2>
    <a href="#!" aria-label="More"><span class="material-symbols" aria-hidden="true">more_vert</span></a>
  </nav>
</header>

<header class="large">…</header>
```

## Subtitle

A subtitle is an `<hgroup>` wrapping the heading and a `<p>`. That is the HTML for a heading plus a subheading; there is no `subtitle` class. Small uses `label-medium`. Medium-flexible grows to 136dp and uses `label-large`. Large-flexible grows to 152dp and uses `title-medium`.

## Medium title

Subtitle

```
<header class="medium">
  <nav aria-label="Main">
    <button type="button" aria-label="Back">
      <span class="material-symbols" aria-hidden="true">arrow_back</span>
    </button>
    <hgroup>
      <h2>Medium title</h2>
      <p>Subtitle</p>
    </hgroup>
    <a href="#!" aria-label="More"><span class="material-symbols" aria-hidden="true">more_vert</span></a>
  </nav>
</header>
```

## Fixed

Add `fixed` to pin a top bar with `position: sticky`. No wrapper is required. At rest the bar is `surface`, the same as the page. Once content scrolls under it, supporting browsers fill it with `surface-container` via `animation-timeline: scroll()` so it separates from the body — that is the M3 Expressive treatment, not a shadow. Without that API the bar stays at rest.

The documentation header on this site is a fixed small bar. A second fixed bar on this page would sit on top of it, so the live example is the site header itself.

```
<header class="fixed">
  <nav aria-label="Main">
    <h2>Title</h2>
    <a href="#!" aria-label="Search"><span class="material-symbols" aria-hidden="true">search</span></a>
  </nav>
</header>
```

## Color

The default fill is `surface`. Color utilities win because they live in the utilities layer — put `primary on-primary-text` (or any fill + `on-*` pair) on the header. Icons inherit the header color. Set `--md-comp-top-app-bar-trailing-icon-color` to `var(--md-sys-color-on-surface-variant)` if you want the spec’s muted trailing icons.

## Primary

```
<header class="primary on-primary-text">
  <nav aria-label="Main">
    <h2>Primary</h2>
  </nav>
</header>
```

Component tokens you can set on the header (or on `:root`):

| Token | Default |
| --- | --- |
| `--md-comp-top-app-bar-container-color` | `--md-sys-color-surface` |
| `--md-comp-top-app-bar-scrolled-container-color` | `--md-sys-color-surface-container` |
| `--md-comp-top-app-bar-headline-color` | `--md-sys-color-on-surface` |
| `--md-comp-top-app-bar-leading-icon-color` | `inherit` (spec: `on-surface`) |
| `--md-comp-top-app-bar-trailing-icon-color` | `inherit` (spec: `on-surface-variant`) |
| `--md-comp-top-app-bar-container-height` | 64px |
| `--md-comp-top-app-bar-leading-icon-size` | 24px |

## Menu

Point a `menu-trigger` at a `<menu>` whose `id` matches `data-target`. `AutoInit()` starts every `.menu-trigger`.

-   one
-   two

-   three

## Title

-   Sass
-   Components
-   Menu

```
<menu id="menu1">
  <li><a href="#!">one</a></li>
  <li><a href="#!">two</a></li>
  <li class="divider" role="separator"></li>
  <li><a href="#!">three</a></li>
</menu>
<header>
  <nav aria-label="Main">
    <h2>Title</h2>
    <menu>
      <li>
        <a class="menu-trigger" href="#!" data-target="menu1">
          Menu<span class="material-symbols right" aria-hidden="true">arrow_drop_down</span>
        </a>
      </li>
    </menu>
  </nav>
</header>
```

To initialize the menu yourself:

```
document.addEventListener('DOMContentLoaded', function() {
  const elems = document.querySelectorAll('.menu-trigger');
  Expressive.Menu.init(elems);
});
```

Menus open on click by default (`hover: false`). Pass `{ hover: true }` to open on hover instead.

## Search

The search app bar is a `<search class="search-bar">` in the nav, in place of the headline. Icons beside it sit outside the search; icons inside it stay on the search-bar. The input is centered. Focusing the field opens the related `.search-view`.

```
<header>
  <nav aria-label="Main">
    <button type="button" aria-label="Menu">
      <span class="material-symbols" aria-hidden="true">menu</span>
    </button>
    <search class="search-bar" aria-label="Search">
      <span class="material-symbols" aria-hidden="true">search</span>
      <input type="search" placeholder="Search" aria-label="Search">
    </search>
  </nav>
</header>
```

A `<form>` in the nav still fills the space between the leading action and anything after it. The input is unstyled against the bar — no extra field class.

## Mobile collapse

Hide the destination menu below the Expanded breakpoint and put a `navigation-drawer-trigger` in the leading slot. The trigger stays visible at every size — it is the page-navigation control, not collapse chrome. Pair it with a `navigation-drawer` whose id matches `data-target`. The sidenav element itself must not be a child of the `<nav>`.

## Title

-   Sass
-   Components
-   JavaScript
-   Mobile

-   Sass
-   Components
-   JavaScript
-   Mobile

```
<header>
  <nav aria-label="Main">
    <button type="button" data-target="mobile-demo" class="navigation-drawer-trigger" aria-label="Open menu">
      <span class="material-symbols" aria-hidden="true">menu</span>
    </button>
    <h2>Title</h2>
    <menu class="hide-on-med-and-down">
      <li><a href="#!">Sass</a></li>
      <li><a href="#!">Components</a></li>
    </menu>
  </nav>
</header>

<nav aria-label="Main">
  <ul class="navigation-drawer" id="mobile-demo">
    <li><a href="#!">Sass</a></li>
  </ul>
</nav>
```

After you add the trigger and the navigation drawer, initialize NavigationDrawer (or let `AutoInit()` do it).

```
document.addEventListener('DOMContentLoaded', function() {
  Expressive.NavigationDrawer.init(document.querySelectorAll('.navigation-drawer'));
});
```
