# Banners

> A prominent message that stays put until the user deals with it.

## Anatomy

A banner carries an important message at the top of a view, in the flow of the page, with one or two actions on it. It stays until the user acts — nothing dismisses it on a timer, and nothing about it is scripted.

A `<div class="banner">` is the container. A `<p>` is the message. Everything else is optional and in this order: a leading `<span class="material-symbols">`, a `<div class="actions">` of buttons, and a trailing `.icon-button` that closes it. Removing the banner from the page is what "closing" means, and that is the page's job — there is no plugin to call.

You're offline. Edits are saved locally and will sync later.

Retry

```
<div class="banner">
  <span class="material-symbols" aria-hidden="true">cloud_off</span>
  <p>You're offline. Edits are saved locally and will sync later.</p>
  <div class="actions">
    <button class="button text" type="button">Retry</button>
  </div>
  <button class="icon-button" type="button" aria-label="Dismiss">
    <span class="material-symbols" aria-hidden="true">close</span>
  </button>
</div>
```

## Banner, snackbar or dialog

Three components tell the user something, and the difference between them is how much of the user's attention they are entitled to take. Reach for the least of the three that does the job.

| Component | Lifetime | Blocks the page | Use it when |
| --- | --- | --- | --- |
| [Snackbar](/snackbar.html.md) | 4–10 seconds, then gone | No — it floats over the page | Confirming something that already happened. Missing it costs nothing: "Photo saved", "Message sent". |
| Banner | Until the user acts on it | No — it sits in the flow and pushes content down | A condition that persists and that the user can keep working around. Offline, a failed sync, an expiring trial, a cookie choice. |
| [Dialog](/dialogs.html.md) | Until the user answers | Yes — nothing else is reachable | The user cannot continue without deciding, or the decision destroys something. |

Two rules of thumb follow from that. If missing the message is harmless, it is a snackbar — a banner that reports a completed action is a banner that never earns its dismissal. And if the user can usefully carry on with the message on screen, it is not a dialog: blocking the page for something the user is allowed to ignore is how a product teaches people to dismiss its dialogs unread.

One banner at a time, at the top of the content it is about. Two stacked banners are two messages competing, and the second one loses.

## Basic

The basic banner is a single row 56dp tall: icon, message, actions, close. The message grows the row when it wraps. Anything you leave out simply is not there — a message on its own is a valid banner.

Your trial ends in three days.

See plans

```
<div class="banner">
  <p>Your trial ends in three days.</p>
  <div class="actions">
    <button class="button text" type="button">See plans</button>
  </div>
</div>
```

Below 600dp the actions take a line of their own under the message and the row grows to 112dp, because a phone-width row cannot hold a message and two buttons side by side without shrinking the message to nothing.

## Standard and vibrant

Two colour variants. A standard banner sits on `surface-container` and is the default — quiet enough to live above content without competing with it. Add `vibrant` for `primary-container`, when the message is the most important thing on the screen. Both keep their close button in `primary`.

A new version is ready to install.

Later Restart

```
<div class="banner vibrant">
  <span class="material-symbols" aria-hidden="true">system_update</span>
  <p>A new version is ready to install.</p>
  <div class="actions">
    <button class="button text" type="button">Later</button>
    <button class="button text" type="button">Restart</button>
  </div>
  <button class="icon-button" type="button" aria-label="Dismiss update notice">
    <span class="material-symbols" aria-hidden="true">close</span>
  </button>
</div>
```

`square` flattens the 28dp corners to nothing, for a banner that runs flush under an [app bar](/navbar.html.md) or against the edges of the window. It applies to the basic banner only: ExpressiveCSS gives the rich layout one shape and no square counterpart, so `class="banner rich square"` is a rich banner with rounded corners.

Connection lost. Reconnecting…

```
<div class="banner square">
  <span class="material-symbols" aria-hidden="true">wifi_off</span>
  <p>Connection lost. Reconnecting…</p>
</div>
```

## Rich

`rich` gives the banner a heading, room for a longer message, and either a 24dp icon or an 80dp image beside it. The actions move to their own row underneath. Use it when the message needs a sentence rather than a clause — otherwise the basic row says the same thing in a third of the height.

### We updated our privacy policy

Analytics cookies are now off by default, and you can change what we collect at any time from your account settings.

Read the policy Got it

```
<div class="banner rich vibrant">
  <span class="material-symbols" aria-hidden="true">shield_person</span>
  <h3>We updated our privacy policy</h3>
  <p>
    Analytics cookies are now off by default, and you can change
    what we collect at any time from your account settings.
  </p>
  <div class="actions">
    <button class="button text" type="button">Read the policy</button>
    <button class="button text" type="button">Got it</button>
  </div>
  <button class="icon-button" type="button" aria-label="Dismiss privacy notice">
    <span class="material-symbols" aria-hidden="true">close</span>
  </button>
</div>
```

An `<img>` takes the icon's place. It is drawn as an 80dp square with square corners, cropped to fit, and it needs an `alt` — descriptive when it says something the heading and the message do not, empty when it is decoration, as it is here.

### Your photo book is ready

Twenty-four pages, printed and bound. It ships within two business days once you approve the proof.

View proof

```
<div class="banner rich">
  <img src="/photo-book.jpg" alt="">
  <h3>Your photo book is ready</h3>
  <p>
    Twenty-four pages, printed and bound. It ships within two
    business days once you approve the proof.
  </p>
  <div class="actions">
    <button class="button text" type="button">View proof</button>
  </div>
</div>
```

The rich layout is a named grid, so the five parts — leading element, heading, message, actions, close — can be written in whatever order reads best and each one collapses its track when it is absent. Pick the heading level that fits the page's outline; the banner styles whichever of `h1`–`h6` it finds.

## Semantics

A banner is not `role="banner"`. That role is the page header landmark: a page has one of those, and it may have several banners, so announcing each one as the site header buries the real header among them. The [semantics suite](https://github.com/BaezFJ/ExpressiveCSS/blob/master/SEMANTICS.md) blocks both spellings of that confusion — `<header class="banner">` and `role="banner"` on the container.

The action row is `.actions` and never a `<nav>`. Retry, restart and dismiss are commands, not destinations, and a landmark for them would be one more identical entry in the landmark menu.

Icons are decoration: the message says what the leading icon says, and the close button carries its own `aria-label`, so both are `aria-hidden="true"`. A banner that appears while the user is on the page — a connection dropping, a sync failing — should announce itself: put `role="status"` on it, which is polite and does not move focus. A banner that is there when the page loads has already been read in document order and needs nothing.

## Tokens

Set these on the banner itself, or in a rule of your own that picks out the banners you want to change — `.notice-area .banner { … }`. They are declared on the component, so a value set on an ancestor *element* is shadowed by the banner's own default rather than inherited. The colours are shared by both variants; the geometry belongs to one layout or the other.

| Token | Default |
| --- | --- |
| `--md-comp-banners-color` | `var(--md-sys-color-surface-container)` |
| `--md-comp-banners-body-text-color` | `var(--md-sys-color-on-surface)` |
| `--md-comp-banners-title-text-color` | `var(--md-sys-color-on-surface)` |
| `--md-comp-banners-icon-color` | `var(--md-sys-color-on-surface)` |
| `--md-comp-banners-close-button-color` | `var(--md-sys-color-primary)` |
| `--md-comp-banners-basic-height` | `56px` (`112px` below 600dp) |
| `--md-comp-banners-basic-shape` | `28px` (`0` when `square`) |
| `--md-comp-banners-basic-leading-space` | `4px` |
| `--md-comp-banners-basic-trailing-space` | `4px` |
| `--md-comp-banners-basic-top-space` | `4px` |
| `--md-comp-banners-basic-bottom-space` | `4px` |
| `--md-comp-banners-basic-icon-container-size` | `48px` |
| `--md-comp-banners-basic-icon-size` | `24px` |
| `--md-comp-banners-basic-body-text-top-space` | `14px` |
| `--md-comp-banners-basic-body-text-bottom-space` | `14px` |
| `--md-comp-banners-basic-no-icon-body-text-leading-space` | `16px` |
| `--md-comp-banners-basic-actions-between-space` | `8px` |
| `--md-comp-banners-basic-actions-leading-space` | `8px` |
| `--md-comp-banners-basic-actions-trailing-space` | `8px` |
| `--md-comp-banners-rich-shape` | `28px` |
| `--md-comp-banners-rich-leading-space` | `12px` |
| `--md-comp-banners-rich-trailing-space` | `12px` |
| `--md-comp-banners-rich-top-space` | `12px` |
| `--md-comp-banners-rich-bottom-space` | `12px` |
| `--md-comp-banners-rich-icon-size` | `24px` |
| `--md-comp-banners-rich-icon-text-space` | `4px` |
| `--md-comp-banners-rich-image-size` | `80px` |
| `--md-comp-banners-rich-image-text-space` | `8px` |
| `--md-comp-banners-rich-leading-element-leading-space` | `4px` |
| `--md-comp-banners-rich-with-image-leading-space` | `20px` |
| `--md-comp-banners-rich-title-text-top-space` | `14px` |
| `--md-comp-banners-rich-title-text-bottom-space` | `14px` |
| `--md-comp-banners-rich-actions-between-space` | `8px` |
| `--md-comp-banners-rich-actions-top-space` | `12px` |

The message and the rich heading both carry the [body-medium](/typography.html.md) type role — the heading at weight 500, which is Material's emphasized body-medium. Action buttons are ordinary [text buttons](/buttons.html.md) and take their colour from the theme, not from the banner.
