Announcement Bar
One short, authored site notice per page: a closure, a deadline, shipping terms, a policy change. An aside labelled "Announcement" with at most one link, an optional countdown and an optional dismiss button. It is not a Toast, never rotates messages and never carries form feedback.
import { AnnouncementBar } from '@fairgarden-private/design/components/AnnouncementBar'
Place it full width at the top of the page; it sets its own content container. The message is up to two lines at base and one from 768 px; it is never truncated and never sticky, so it scrolls away with the page. The bar is 36 px tall for text alone and 44 px once it holds a link or the dismiss.
Bars and fields
Bars and fields
kind="bar" (default) is a page-ground bar (white, paper or the page's pastel through preset, or the surrounding ground when it names none) that always draws its bottom rule. kind="field" sets the notice in a full-container field (forest by default, leaf, amber or brick; never pink or royal) whose edge replaces the rule. voice="mono" sets dated notices in data caps, and voice="dual" adds one serif caps phrase through AnnouncementBarAccent. The countdown's boxed digits update once a minute and never flip; they fill in after the page loads. dismissible removes the bar at once, and storageKey remembers that per viewer.
'use client'
import * as React from 'react'
import {
AnnouncementBar,
AnnouncementBarAccent,
} from '@fairgarden-private/design/components/AnnouncementBar'
import styles from './bars.module.css'
/** A page-ground bar with its rule, link and dismiss; a mono countdown; a forest field bar; a dual-voice record. */
export function AnnouncementBarBars() {
const [dismissals, setDismissals] = React.useState(0)
return (
<div className={styles.stack}>
<AnnouncementBar
key={dismissals}
preset="white"
link={{ href: 'https://example.org/hours', label: 'See Hours' }}
dismissible
>
The visitor center is closed 24–26 December.
</AnnouncementBar>
<AnnouncementBar
voice="mono"
countdown={{ end: '2026-12-31T17:00:00Z', expired: 'Registration closed' }}
>
Registration closes in
</AnnouncementBar>
<AnnouncementBar
kind="field"
link={{ href: 'https://example.org/walks', label: 'Book a Walk' }}
>
Guided spring walks are open for booking.
</AnnouncementBar>
<AnnouncementBar kind="field" preset="amber" voice="dual" record>
Product recall: <AnnouncementBarAccent>Trail Mix No. 4</AnnouncementBarAccent>, lots 12–19
</AnnouncementBar>
<p className={styles.status}>
<button type="button" className={styles.reset} onClick={() => setDismissals((n) => n + 1)}>
Show the dismissed bar again
</button>
</p>
</div>
)
}
In print
Hidden, unless record marks a notice that changes the page's meaning: it prints once, between two 0.75 pt rules, with its link's short URL. A countdown prints its end date ("Ends 30 Sept 2026").
API Reference
AnnouncementBar
The announcement bar. Never sticky, never rotating, never truncated with
an ellipsis; it scrolls away with the page. Hidden in print unless it is
a record, whose countdown prints its end date.
| Prop | Type | Description |
|---|---|---|
countdown | | Boxed countdown digits; a polite live region announces at most once a minute. |
dismissLabel | | The dismiss button’s accessible name. Default “Dismiss announcement”. |
dismissible | | Adds the dismiss button ( |
kind | |
|
link | | The one link, after the message: underlined at rest in |
onDismiss | | Called after the bar is dismissed. |
preset | | The bar’s page ground: |
primary | | Primary Radix scale: message, digits, cells, glyph and focus ring. Never defaulted; omitted, it inherits the bar’s preset [D133]. |
record | | A notice of record (a legal change, a recall): it prints once, between
two 0.75 pt rules. Default |
ruled | | The bottom rule is required on every page-ground bar. |
secondary | | Secondary Radix scale: the link underline and its hover ink. Never defaulted. |
storageKey | | Remembers the dismissal per viewer under this key (browser storage), so the bar stays gone on later visits. Change the key for a new notice. |
voice | |
|
children | | The message: one short notice, authored; ≤ 2 lines at base, 1 from |
AnnouncementBarAccent
The dual voice’s one serif caps phrase, set inside the message at the
run’s cap height (Rocco’s two-voice bar). Use it once, with voice="dual".
Additional types
announcementBar
type announcementBar = announcementBarAnnouncementBarAccentProps
Props for AnnouncementBarAccent: span props.
type AnnouncementBarAccentProps = React.ComponentPropsWithRef<'span'>AnnouncementBarProps
Props for AnnouncementBar: aside props, the message, link, voice,
record, countdown and dismissal, the kind with its preset, and the color
axes. ruled is required with kind: bar and excluded with kind: field.
type AnnouncementBarProps = AnnouncementBarBarProps | AnnouncementBarFieldPropsAnnouncementCountdown
The countdown: boxed digits to an end time, which print as the end date.
type AnnouncementCountdown = {
/** The end, a Date or an ISO 8601 string. */
end: Date | string;
/** The text that replaces the digits at zero, e.g. "Sale ended". */
expired: React.ReactNode;
/**
* The printed end date line. Default "Ends 30 Sept 2026", formatted from
* `end` in `locale` and the reader's time zone once the page has loaded.
*/
endLabel?: string;
/** The locale for the default end label. Default `en-GB`. */
locale?: string;
/** Unit labels after the day, hour and minute cells. Default `d`, `h`, `min`. */
units?: [string, string, string];
}AnnouncementField
The fields a full-container bar may take [D180]: never pink, never royal.
type AnnouncementField = 'forest' | 'leaf' | 'amber' | 'brick'Specification: DESIGN-SYSTEM.md §11.4 (announcement bar; a page-ground bar or a full-container field per D180).