Announcement bar

A top banner that rotates messages, counts down, and collapses smoothly when dismissed.

pnpm dlx shadcn@latest add @uiarc/announcement-bar
Live · keyboard ready

Fieldwork 4.0 is here: docs, plans, and cycles in one place

  • Site-wide promotions, launches, or maintenance notices at the top of every page.
  • Rotating two to four short announcements in one slim bar.
  • A sale banner with a live countdown to its end.
  • Use alert for a message tied to one section or form.
  • Use toast for feedback on something the visitor just did.
  • Use cookie-consent for consent choices.

Installation

Add Announcement bar with the shadcn CLI, or copy the source by hand.

pnpm dlx shadcn@latest add @uiarc/announcement-bar

Adds the component and its local dependencies, and installs motion, lucide-react. First time? Add the @uiarc registry to components.json, or use the full URL:

example.tsx
import { AnnouncementBar } from "@/registry/components/announcement-bar/announcement-bar"; export function SiteBanner() {  return (    <AnnouncementBar      id="fall-sale-2026"      tone="inverted"      messages={[        { id: "sale", message: "Fall sale: 30% off annual plans.", countdown: { to: "2026-10-01T00:00:00Z", label: "Ends in" }, action: { label: "See plans", href: "/pricing" } },        { id: "launch", message: "Workflows are now in beta.", action: { label: "Read more", href: "/blog/workflows" } },      ]}    />  );}

API reference

2 parts. The first is the root.

AnnouncementBar

A slim top-of-page bar that rotates messages with a timer ring, supports a call to action and live countdown, and remembers dismissal.

PropTypeDefaultDescription
messagesRequiredAnnouncement[]–Messages: { id, message, action?, countdown? }. action is { label, href?, onClick? }; countdown is { to, label? }.
idstring–Remembers dismissal in localStorage under arc-announcement:<id>. Change it to show a new campaign again.
openboolean–Controlled visibility. Stored dismissal is ignored when set.
defaultOpenbooleantrueStarting visibility when uncontrolled.
onOpenChange(open: boolean) => void–Called with false when the visitor dismisses the bar.
indexnumber–Controlled index of the visible message.
defaultIndexnumber0Starting message when uncontrolled.
onIndexChange(index: number) => void–Called when rotation or the arrows change the message.
intervalnumber6000Milliseconds each message stays before the next one.
autoPlaybooleantrueRotates automatically. Off when the visitor prefers reduced motion.
controlsbooleanfalseShows previous, next, and the pause ring when there are several messages. Off by default: only the close button shows and messages still rotate.
dismissiblebooleantrueShows the dismiss button.
tone"neutral" | "inverted""neutral"Muted surface, or foreground-colored bar with background text.
onAction(announcement: Announcement) => void–Called when a message's call to action is pressed, after its own onClick.
onCountdownEnd(announcement: Announcement) => void–Called once when a message's countdown reaches zero.
labelstring"Announcements"Accessible name of the region.
classNamestring–Class on the section.
refRef<HTMLElement>–The section element.

clearAnnouncementDismissal

Forgets a remembered dismissal so the bar with this id shows again.

PropTypeDefaultDescription
idRequiredstring–The id passed to AnnouncementBar.
Tab
Moves through the call to action and dismiss button, plus previous, pause, and next when controls is on. Focus inside pauses rotation.
EnterorSpace
Presses the focused control.
  • The bar is a labelled section; with several messages it is a carousel and each message a slide labelled n of total.
  • The viewport is aria-live off while rotating and polite while paused, so auto-rotation is not read aloud.
  • With controls, the pause ring is a toggle button with aria-pressed and previous and next buttons control the slides region. Without controls, rotation still pauses on hover and focus.
  • Countdowns are role="timer" with aria-live off and a spoken label in hours and minutes.
  • Rotation pauses on hover, keyboard focus inside, or a hidden tab.
  • Next messages rise from below and leave upward (previous runs the other way) while the viewport springs to the new height.
  • With controls, the ring around the pause button fills linearly over the interval, stops where it is on pause, and finishes the rest on resume.
  • Countdown digits drop in from above; dismissing collapses the bar's height so the page below eases up.
  • Reduced motion turns rotation off, swaps messages and digits with fades, and removes the height collapse.
  • Wide bars mirror the controls with an empty column so the message stays centered on the page.
  • The bar is an inline-size container; at 560px and below messages align to the start edge instead of centering.
  • Messages wrap on small screens and the viewport springs to the wrapped height; icon buttons are 32px.
  • One linear motion value drives the ring; it stops while paused, hidden, or dismissed.
  • A countdown ticks with one timeout per second, waking just after each whole second.

Notes for AI

Give your coding assistant the Markdown reference instead of screenshots.

  • Place it above the site header. With an id, dismissal persists; call clearAnnouncementDismissal(id) or change the id to show it again.
  • Keep messages to one short sentence; the call to action is a link when href is set, a button otherwise.
  • For a standalone countdown elsewhere on the page use countdown; this bar has its own lighter timer.

The full library index for assistants is at /llms.txt.