Components / Feedback

AnnouncementBar

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

Install

npx shadcn@latest add https://irisui.dev/r/announcement-bar.json
import { AnnouncementBar } from "@/components/iris/announcement-bar/announcement-bar";
Registry item announcement-barBrings in foundationRegistry JSON

Preview

AnnouncementBar

A slim bar for the top of a page that rotates messages, can count down to a deadline, and collapses smoothly when dismissed.

When to use

  • Site-wide product news, promotions, and events with a call to action.
  • Time-boxed campaigns that need a live countdown ("Ends in 2d 05:59:58").
  • Not for problems tied to a section of the page: use Alert. Not for confirmations of an action: use Toast.

Usage

import { AnnouncementBar } from "@/components/iris/announcement-bar/announcement-bar";

h(AnnouncementBar, {
  id: "first-month-free",
  controls: true,
  messages: [
    {
      id: "pg18",
      message: "Postgres 18 is now first class on every plan.",
      action: { label: "Read the changelog", href: "/changelog" },
    },
    {
      id: "trial",
      message: "Your first month on any plan is free.",
      action: { label: "View plans", href: "/pricing" },
      countdown: { to: "2026-10-31T23:59:00Z", label: "Ends in" },
    },
  ],
});

Props

Prop Type Default Description
messages { id, message: ReactNode, action?: { label, href?, onClick? }, countdown?: { to, label? } }[] — Required. One or more announcements.
id string — Remembers dismissal in localStorage; change it to show a new campaign again.
open / defaultOpen / onOpenChange boolean / boolean / (open) => void — / true / — Controlled or uncontrolled visibility.
index / defaultIndex / onIndexChange number / number / (i) => void — / 0 / — Visible message.
interval number 6000 Milliseconds per message.
autoPlay boolean true Rotate automatically; pauses on hover, focus, or a hidden tab, and is off under reduced motion.
controls boolean false Adds previous, next, and a pause ring when there are several messages.
dismissible boolean true Shows the close button.
tone "neutral" | "inverted" "neutral" Muted surface, or a high-contrast inverted bar.
onAction (announcement) => void — Called when a call to action is used.
onCountdownEnd (announcement) => void — Called when a message's countdown reaches zero.
label string "Announcements" Accessible name of the region.
className string — Extra class.

clearAnnouncementDismissal(id) (Iris.clearAnnouncementDismissal) forgets a dismissal remembered under that id, so the bar shows again on its next mount (for example from a "Show announcements" setting or in tests).

Notes

  • Renders a labelled region. The message is aria-live="polite" only while rotation is stopped (paused, hovered, focused, or a single message), so auto-rotation never chatters. Controls are labelled "Previous announcement", "Next announcement", and pause/play.
  • Each new message rises in while the bar springs to its height; dismissing collapses the height so the page eases up.
  • Reads --hover / --ink (neutral) or --ink / --page (inverted), --line, --ink-2, --text-sm, --tracking-body.