Skip to main content

Announcement Bar

3 min readStableIntermediate

A site-wide dismissible announcement bar can be activated by setting environment variables. app/layout.tsx reads them and mounts the bar above everything else in the body, so it sits over the sidebar, the header, and the page. The bar renders only when both the ID and message are set, and dismissals persist per announcement ID via localStorage.

Quick Start

Enable the bar with an ID and message.

Bash
Bash
NEXT_PUBLIC_ANNOUNCEMENT_ID=launch
NEXT_PUBLIC_ANNOUNCEMENT_MESSAGE="Welcome to our new docs"

That's a centered message in brand color with a close button on the right. The strip is a role="region" labelled aria-label="Announcement", and the close button carries aria-label="Dismiss announcement".

Adding Options

Add a link. The link renders only when both the href and label are set — the component's prop types pair them, so half a link is no link.

Bash
Bash
NEXT_PUBLIC_ANNOUNCEMENT_ID=launch
NEXT_PUBLIC_ANNOUNCEMENT_MESSAGE="Welcome to our new docs"
NEXT_PUBLIC_ANNOUNCEMENT_HREF=/getting-started/introduction
NEXT_PUBLIC_ANNOUNCEMENT_LINK_LABEL="Get started"

The link renders inline after the message text, underlined, and drops the underline on hover. An internal path like the one above navigates in place.

Advanced

Pin the bar so readers can't close it, and point it at an external URL. An href starting with http://, https://, or // opens in a new tab with rel="noopener noreferrer".

Bash
Bash
NEXT_PUBLIC_ANNOUNCEMENT_ID=2026-key-rotation
NEXT_PUBLIC_ANNOUNCEMENT_MESSAGE="Rotate your API keys before March 1"
NEXT_PUBLIC_ANNOUNCEMENT_HREF=https://status.example.com/key-rotation
NEXT_PUBLIC_ANNOUNCEMENT_LINK_LABEL="Read the advisory"
NEXT_PUBLIC_ANNOUNCEMENT_DISMISSIBLE=false

Only the exact string false turns dismissal off. Any other value — 0, no, an empty string, or the variable left unset — keeps the close button.

Dismissals are stored in localStorage under owndocs:announcement-dismissed:<id>. Give the next announcement a fresh ID and the bar comes back for everyone who closed the last one.

Three behaviors are worth knowing before you ship a banner:

  • A dismissible bar starts hidden and appears after the first client effect reads localStorage. That's what stops an already-dismissed banner from flashing on every page load. A pinned bar (DISMISSIBLE=false) skips the lookup and shows immediately.
  • When localStorage is unreachable — Safari private browsing, a locked-down browser profile — the read failure falls back to showing the bar, and the write failure is swallowed so the close click still hides it for the session.
  • An empty message renders nothing even when the ID is set, so clearing NEXT_PUBLIC_ANNOUNCEMENT_MESSAGE is enough to take a banner down.

These are NEXT_PUBLIC_* variables read at module scope, so their values are baked into the client bundle at build time. Changing a banner means a rebuild and redeploy, not just a server restart.

Options

NEXT_PUBLIC_ANNOUNCEMENT_IDenv

Dismissal key. Required with the message to render the bar. Used as the localStorage suffix, so a new ID re-shows the bar for every reader.

NEXT_PUBLIC_ANNOUNCEMENT_MESSAGEenv

Banner message. Required with the ID to render the bar; an empty value hides it.

NEXT_PUBLIC_ANNOUNCEMENT_HREFenv

Optional link target. Internal paths and external URLs are accepted. An http://, https://, or // prefix marks it external and adds target="_blank" with rel="noopener noreferrer".

NEXT_PUBLIC_ANNOUNCEMENT_LINK_LABELenv

Optional link text. The link renders only when both the href and label are set.

NEXT_PUBLIC_ANNOUNCEMENT_DISMISSIBLEenvDefault: true

Set to exactly false to hide the close button. Any other value keeps dismissal on.

localStorage keystringDefault: owndocs:announcement-dismissed:<id>

Where the dismissal flag is written, as the string true. Clearing it brings the bar back for that reader.

landmarkstringDefault: Announcement

The bar is a role="region" with aria-label="Announcement"; the close button uses aria-label="Dismiss announcement".

Was this page helpful?