Cmpnts

Menu

Organisms

Header

The band at the top of a page or app, holding the Brand, the main navigation and global actions.


Code
HTML
<div class="header">
  <div class="header__bar">
    <a href="/" class="brand"><span class="brand__name">Woodland Plants</span></a>
    <nav class="header__nav tab-list tab-list--plain tab-list--scrollable @max-3xl:hide" aria-label="Main, example">
      <ul>
        <li><a href="/plants" class="tab" aria-current="page"><span class="tab__text">Plants</span></a></li>
        <li><a href="/borders" class="tab"><span class="tab__text">Borders</span></a></li>
      </ul>
    </nav>
    <div class="cluster gap-xs">
      <button type="button" class="button button--strong button--accent @max-3xl:hide">Sign in</button>
      <button type="button" class="button button--plain button--icon @3xl:hide" popovertarget="default-header-menu" aria-label="Open site menu">
        <svg class="icon" width="1em" height="1em" aria-hidden="true" focusable="false"><use href="#Navigation"/></svg>
      </button>
      <div id="default-header-menu" popover class="popover">
        <menu class="menu" aria-label="Site menu">
          <li><a href="/plants" class="button" aria-current="page"><span>Plants</span></a></li>
          <li><a href="/borders" class="button"><span>Borders</span></a></li>
          <li><a href="/sign-in" class="button"><span>Sign in</span></a></li>
        </menu>
      </div>
    </div>
  </div>
</div>

Why it exists

The top of the page is where people expect to find out where they are and how to get elsewhere. A Header gives that one consistent place, as a real <header>, so screen reader users can jump to it as the banner landmark.

It draws the band and lays out its rows, and everything in a row styles itself. So a Brand, a Tab List or a Button looks the same here as anywhere, and the Header’s only opinions are about the band. Its bars share the site width with Wrapper, so the Header lines up with the page.

It ships no script and no mobile menu. Because the Header is a container, a menu Button can replace the navigation by the Header’s own width, and that menu is a Popover or a Dialog, which already handle focus and Escape.

When to use

  • Once per page, at the top, for the Brand, the main navigation and global actions.
  • As an app toolbar, with --compact.
  • Not for a section’s own heading and actions: that is a Card header or a row in the page.
  • Not for a site-wide announcement: that is a Banner Dock.
  • Not for section navigation: that goes in a Sidebar.

Rules

  • One banner: a <header> that is a direct child of <body> (or .app) is the banner landmark. Use one per page; it needs no aria-label. A <header> inside <main>, <article> or <section> isn’t a landmark.
  • The Skip Link comes first, before the Header.
  • Navigation is a <nav> with an aria-label; the current page has aria-current="page".
  • Narrow widths: the Header is a container, so @max-3xl:hide and @3xl:hide swap the navigation for a menu Button by the Header’s own width. The menu Button opens a Popover (.popover with a .menu of links) or a Dialog, or sets aria-expanded and aria-controls on a panel the product’s script shows.
  • Focus Not Obscured (WCAG 2.4.11): while a sticky header is on the page, the page’s scroll-padding-block-start is --header-height (a target-sized bar, its padding and border), so a focused element scrolls clear of it. If the Header is taller (two rows), set --header-height on :root. The Sidebar reads the same hook for its sticky offset.

Keyboard and screen readers

The Header adds no behaviour of its own. Links, Buttons and landmarks do this natively.

  • Tab reaches the Skip Link first, then the Brand, the navigation and the actions, in source order.
  • A scrollable Tab List scrolls each Link into view as it takes focus.
  • Enter or Space on a popovertarget menu Button opens the Popover, and the browser exposes its expanded state. The next Tab moves into the Popover.
  • Escape closes the Popover, and focus returns to the Button.
  • A menu built with a script is the product’s to make: it sets aria-expanded and aria-controls on the Button, and manages its own focus and Escape.
  • A screen reader finds the Header as the banner, names the navigation from its aria-label and announces the current page from aria-current="page".

The Whole Page’s Header

A real <header>, so it can’t be shown live on this page, which has its own.

HTML
<a href="#main" class="skip-link">Skip to content</a>
<header class="header header--sticky">
  <div class="header__bar">
    <a href="/" class="brand"><span class="brand__name">Woodland Plants</span></a>
    <nav class="header__nav tab-list tab-list--plain tab-list--scrollable @max-3xl:hide" aria-label="Main">
      <ul>
        <li><a href="/plants" class="tab" aria-current="page"><span class="tab__text">Plants</span></a></li>
        <li><a href="/borders" class="tab"><span class="tab__text">Borders</span></a></li>
      </ul>
    </nav>
    <div class="cluster gap-xs">
      <button type="button" class="button button--strong button--accent @max-3xl:hide">Sign in</button>
      <button type="button" class="button button--plain button--icon @3xl:hide" popovertarget="menu" aria-label="Menu">…</button>
    </div>
  </div>
</header>
<main id="main">…</main>

Two Rows

Code
HTML
<div class="header">
  <div class="header__bar">
    <a href="/" class="brand"><span class="brand__name">Woodland Plants</span></a>
    <nav class="header__nav tab-list tab-list--plain tab-list--scrollable @max-3xl:hide" aria-label="Main, two rows example">
      <ul>
        <li><a href="/plants" class="tab" aria-current="page"><span class="tab__text">Plants</span></a></li>
        <li><a href="/borders" class="tab"><span class="tab__text">Borders</span></a></li>
      </ul>
    </nav>
    <button type="button" class="button">Sign in</button>
  </div>
  <div class="header__bar">
    <nav class="breadcrumb" aria-label="Breadcrumb, example">
      <ol class="small-text">
        <li><a class="link" href="/plants">Plants</a></li>
        <li aria-current="page">Ferns</li>
      </ol>
    </nav>
    <button type="button" class="button button--sm">Edit</button>
  </div>
</div>

Two bars in one <header>, with a rule between them. One landmark, one band.

Do and Don’t

DoDon’t
Use one <header> per page, with the Skip Link before it.Label the banner with aria-label.
Use two __bars for two rows.Add a second header, or a .header-container.
Raise --header-bar-min-size for a taller header.Size the Header from --header-height.
Swap the navigation for a menu Button with @max-3xl:hide and @3xl:hide.Hide the navigation with nothing in its place.
Put .color-scheme-dark on the band for a dark header.Build a layout inside it with a Wrapper and padding utilities.

In Storybook

See also

  • Brand: The product's mark and name, as a Link home.
  • Tabs: A row of Tabs for moving between sections of a site or switching the view of one panel.
  • Breadcrumb: The trail of pages above the current one, as a line of links.
  • Skip Link: A Link that lets keyboard users jump past repeated content to the main content.
  • Footer: The band at the bottom of a page or app, with site links, legal text and contact details.
  • App Shell: The page shell that places the Header, main and footer in rows, with side panes beside the main.
  • Responsive Helpers: Hide something, its labels, or everything but its accessible name, by a condition.

Search the docs