Broadcast Bar System
A top broadcast bar system that stacks multiple announcements, rotates them through a priority queue, supports countdowns, CTAs, and dismissal memory, and springs its height changes so the content below is pushed smoothly.
npx shadcn@latest add https://webberui.com/r/broadcast-bar-system.jsonPlayground
Tune the props live — the code snippet updates as you go, so you can dial in the look you want before copying it.
<BroadcastBarSystem />
Installation
npx shadcn@latest add https://webberui.com/r/broadcast-bar-system.jsonOr, once registries are configured in components.json, install it as @webberui/broadcast-bar-system.
Usage
import { BroadcastBarSystem } from "@/components/ui/broadcast-bar-system";
<BroadcastBarSystem
messages={[
{
id: "sale",
variant: "promo",
priority: 3,
content: "Final hours of the summer sale",
countdownTo: Date.now() + 1000 * 60 * 60 * 2,
cta: { label: "Shop now", href: "/sale" },
},
{
id: "maintenance",
variant: "warning",
priority: 1,
content: "The system will be under maintenance this Sunday at 02:00",
},
]}
/>Announcements are queued from highest to lowest priority and rotate automatically; the ones a user dismisses are remembered in localStorage and do not reappear after a refresh. The broadcast bar itself sits in normal flow layout, and its height transitions with a spring, so the page content below is pushed naturally and smoothly.
Props
BroadcastBarSystem
| Prop | Type | Default | Description |
|---|---|---|---|
messages | BroadcastMessage[] | — | The announcement array, rotated from highest to lowest priority |
rotateInterval | number | 5000 | Automatic rotation interval (milliseconds); set to 0 to disable |
storageKey | string | null | "wb-broadcast-dismissed" | localStorage key used to remember dismissed announcements; null disables persistence |
sticky | boolean | false | Whether it sticks to the top of the container |
onDismiss | (id: string) => void | — | Fires when a single announcement is dismissed |
onEmpty | () => void | — | Fires once when every announcement has been dismissed and the bar collapses to zero height |
BroadcastMessage
| Field | Type | Default | Description |
|---|---|---|---|
id | string | — | Unique identifier, used for rotation positioning and dismissal memory |
content | React.ReactNode | — | The main text content |
priority | number | 0 | Higher numbers rotate in earlier |
variant | "info" | "success" | "warning" | "critical" | "promo" | "info" | Accent color and default icon |
icon | React.ReactNode | — | Custom leading icon, overriding the variant default |
cta | BroadcastCTA | — | Call to action; renders a link when it has an href, otherwise a button |
countdownTo | number | Date | — | Countdown target, showing a live HH:MM:SS countdown |
onCountdownEnd | () => void | — | Fires once when the countdown reaches zero |
dismissible | boolean | true | Whether to show a dismiss button |
How it works
- Priority queue:
messagesis stably sorted bypriorityand only announcements that have not been dismissed are shown; exactly one appears at a time, rotating at a fixed interval. - Countdown:
countdownToaccepts a millisecond timestamp or aDateand updates every 250ms; past one day it showsD天 HH:MM:SS(a day count followed byHH:MM:SS). Reaching zero firesonCountdownEndonce. - Dismissal memory: the ids of dismissed announcements are written to
localStorage(customize it withstorageKeyor turn it off withnull); whenlocalStorageis unavailable it silently degrades to remembering only the current session. - Smooth pushing: the bar measures its content height and transitions its own height with a spring, so switching between announcements of different heights or dismissing them all pushes the content below smoothly or lets it fill back in.
Accessibility
- The broadcast bar is marked with
role="region"plus anaria-label, which makes it easy for assistive technology to locate. - With multiple announcements it provides keyboard-operable navigation dots (
role="tab"), each labeled "item N of M"; the dismiss button carries anaria-label. - Rotation pauses automatically on pointer hover or when keyboard focus enters, so the content does not jump while the user is reading.
- It respects the system "reduce motion" setting: automatic rotation and displacement animations are disabled, height switches instantly, and announcements fade in and out instead.
- The countdown only renders after mount, which avoids the hydration mismatch that depending on
Date.now()would cause.
Skeleton Orchestra
A skeleton-screen orchestration system: when loading finishes, the skeletons solidify into real content one by one in directional waves following the layout.
UI Sound Kit
Lightweight interface sounds — click, hover, success, error and more — synthesized live with Web Audio, with built-in volume control, a global switch, and preference-respecting behavior; no audio files, no extra requests.