---
title: Announcement Banner
description: A dismissible page-edge bar for announcements, promos, and notices
visibility: guest
draft: false
---

# Announcement Banner

The full-width bar at the very top of a page: a launch, a sale, a maintenance
window. It sits on the **content-edge spine**, so its text lines up with the rest
of your page chrome instead of floating on its own margin.

It is **not** an [Alert](/components/alert) — an alert is about the thing the
user is doing right now; an announcement is ambient, site-wide, and dismissible.

## Basic Usage

:::preview{title="A promo bar"}
<x-wirekit::announcement-banner>
    Summer sale — 20% off every plan through Friday.
</x-wirekit::announcement-banner>
:::

## With an action

:::preview{title="An inline call to action"}
<x-wirekit::announcement-banner>
    WireKit v2 is out — chat components, mockups, and a lot more.
    <x-slot:action>
        <x-wirekit::link href="/changelog">Read the changelog</x-wirekit::link>
    </x-slot:action>
</x-wirekit::announcement-banner>
:::

## Intents

`promo` is the marketing default; the state intents carry their usual meaning
for a notice.

:::preview{title="Intents"}
<x-wirekit::stack gap="sm">
    <x-wirekit::announcement-banner intent="promo">Promo — 20% off every plan.</x-wirekit::announcement-banner>
    <x-wirekit::announcement-banner intent="info">Info — a new region is available.</x-wirekit::announcement-banner>
    <x-wirekit::announcement-banner intent="warning">Warning — maintenance on Sunday, 02:00–04:00 UTC.</x-wirekit::announcement-banner>
    <x-wirekit::announcement-banner intent="danger">Danger — the API v1 shutdown is in 7 days.</x-wirekit::announcement-banner>
</x-wirekit::stack>
:::

## Dismissing

A dismissible bar gets a close button. There are two modes:

- **Remembered** (default) — give a `dismissKey` and the dismissal sticks across
  page loads. This is what production wants: the reader clicks the X once and the
  bar stays gone.
- **Session-only** — pass `:persist="false"` for a notice that reappears next
  visit. It needs no key, and because nothing is stored, a re-mount brings it
  back — which is exactly why the demo below can be dismissed and restored.

The preview is session-only, so you can click the close button and bring the bar
back with the preview's replay control (or a reload):

:::preview{title="Dismissible"}
<x-wirekit::announcement-banner :persist="false" label="Summer sale">
    Summer sale — 20% off every plan through Friday.
    <x-slot:action>
        <x-wirekit::link href="/pricing">See pricing</x-wirekit::link>
    </x-slot:action>
</x-wirekit::announcement-banner>
:::

In production you usually want it **remembered**. Give it a `dismissKey`, and
change that key when the message changes — a new announcement should not inherit
the old one's dismissal:

```blade
{{-- 1. The key IS the identity of the announcement — and it remembers --}}
<x-wirekit::announcement-banner dismiss-key="launch-v2" label="v2 launch">
    WireKit v2 is out.
</x-wirekit::announcement-banner>
```

A close button that forgets is worse than none — the user clicks it, the bar
comes back on the next page, and the site feels broken. That is why a bar with
neither a `dismissKey` nor `:persist="false"` has **no** close button at all:
forgetfulness has to be a deliberate choice.

## Sticky

`sticky` keeps the bar in view while the page scrolls. It is opt-in on purpose:
a bar that follows the reader is a much stronger claim on the viewport than most
announcements have earned.

```blade
{{-- 1. Reserve sticky for something genuinely time-critical --}}
<x-wirekit::announcement-banner sticky intent="danger" dismiss-key="api-v1-eol">
    The API v1 shutdown is in 7 days.
</x-wirekit::announcement-banner>
```

Combine it with `position="bottom"` to dock a persistent notice to the foot of the
page (where a thumb reaches on a phone) instead of the top.

## Full width and centered content

The bar always spans the **full page width** — a promo covering half the header
reads as a mistake — and its content is **centered**, so a short message sits in the
middle of the bar however wide the screen gets. That is the whole layout: a
full-bleed strip with a centered notice.

:::preview{title="Full-width bar with a centered message and action" wide}
<x-wirekit::announcement-banner intent="info" label="New region">
    A new region is available — deploy closer to your users in eu-central.
    <x-slot:action>
        <x-wirekit::link href="/regions">See regions</x-wirekit::link>
    </x-slot:action>
</x-wirekit::announcement-banner>
:::

For a bar whose message and controls sit at **opposite edges** of a content column
(a navigation-style layout, not a centered notice), reach for
[navbar](/components/navbar) instead.

## Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `position` | string | `'top'` | `top` or `bottom` |
| `sticky` | bool | `false` | Keep the bar in view while scrolling |
| `intent` | string | `'promo'` | `promo`, `info`, `success`, `warning`, `danger` |
| `dismissKey` | string\|null | `null` | Stable key; enables the close button and persists the dismissal across page loads |
| `persist` | bool | `true` | Whether a dismissal is remembered across page loads. Set `false` for a session-only bar (also enables the close button without a key) |
| `label` | string | `'Announcement'` | Accessible name for the region |
| `scope` | string\|null | `null` | Scoped personalization name |

## Slots

| Slot | Description |
| --- | --- |
| default | The message |
| `action` | An inline link or button |

## Accessibility

- The bar is a **labeled region**, never `role="alert"`. An alert interrupts a
  screen-reader user mid-sentence — the wrong trade for a promo. A region lets
  them find it when they want it and skip it when they do not.
- The close control is a real `<button>` with a real name ("Dismiss Summer
  sale"), never a bare glyph. The X itself is `aria-hidden`.
- `x-cloak` keeps a previously-dismissed bar from flashing on every page load
  before the stored state is read.
- Give the bar a specific `label` — "Announcement" is the fallback, "Summer sale"
  is useful.

## Keyboard Interaction

| Key | Action |
| --- | --- |
| <kbd>Tab</kbd> | Focus the action, then the close button |
| <kbd>Enter</kbd> / <kbd>Space</kbd> | Activate the focused control |

## Pitfalls

- **Do not use it for the thing the user is doing.** That is
  [Alert](/components/alert).
- **Do not stack banners.** Two bars at the top of a page is one too many; the
  second one is never read.
- **Do not reuse a dismiss key for a new message.** The new announcement would
  arrive already dismissed.
- **Do not make it sticky by default.** Ambient news does not deserve permanent
  viewport.

## Design Tokens

| Element | Token |
| --- | --- |
| Content-edge spine | `--padding-wk-x-lg` |
| Vertical padding | `--padding-wk-y-sm` |
| `promo` surface | `--color-wk-accent` / `--color-wk-accent-fg` |
| State surfaces | `--color-wk-{info,success,warning,danger}` mixed 12% over `--color-wk-bg-elevated` |
| Text size | `--text-wk-sm` |
| Focus ring | `--color-wk-ring` |

## Further Reading

- [WAI-ARIA: `region` role](https://www.w3.org/TR/wai-aria-1.2/#region)
- [MDN: `localStorage`](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage)
