motif svelteArc

Announcement Bar ported

One slim line for what everyone should see.

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

Live specimen

Loading demo…

Guidance

When to use

  • For a site-wide note at the top of the page: launches, sales, maintenance.
  • When several messages should rotate on one clock with pause on hover.
  • When a message carries a call to action or a live countdown.

When not to use

  • For transient results of an action — use toast or toast-stack.
  • For persistent, in-flow messages tied to a form — use alert.
  • When people must respond before continuing — use dialog.

Installation

pnpm add sveltearc

Usage

<script lang="ts">
	import AnnouncementBar from '$lib/components/announcement-bar/announcement-bar.svelte';

	const messages = [
		{
			id: 'launch',
			message: 'Aurora is live — see what is new.',
			action: { label: 'Read the notes', href: '/changelog' }
		}
	];
</script>

<AnnouncementBar {messages} id="launch-2026" controls />

Variants & Examples

Rotating with controls

Previous, next and pause buttons across several messages.

<AnnouncementBar {messages} controls />

Countdown

A live countdown beside the message, with onCountdownEnd.

<AnnouncementBar messages={[{ id: 'sale', message: 'Sale ends in', countdown: { to: deadline, label: 'Ends in' } }]} />

Inverted tone

Light-on-dark bar for high-contrast moments.

<AnnouncementBar {messages} tone="inverted" />

API Reference

PropTypeDefaultDescription
messagesAnnouncement[]—The rotating messages. Each has an id, a message (string or Snippet), an optional action and an optional countdown.
idstring—Remembers dismissal under this id. Change the id to show a new campaign to everyone again.
openboolean—Whether the bar is shown. Leave it out to let the component manage it.
defaultOpenbooleantrueInitial visibility when uncontrolled.
onOpenChange(open: boolean) => void—Fired with false on dismiss.
indexnumber—Index of the visible message. Leave it out for internal rotation.
defaultIndexnumber0Initial message when uncontrolled.
onIndexChange(index: number) => void—Fired when rotation advances or the visitor steps.
intervalnumber6000Milliseconds each message stays before the next one.
autoPlaybooleantrueRotate automatically. Pauses on hover, focus, or a hidden tab; off under reduced motion.
controlsbooleanfalseShow previous, next, and pause controls when there are several messages.
dismissiblebooleantrueShow the dismiss button.
tone'neutral' | 'inverted''neutral'Colour story of the bar.
onAction(announcement) => void—Fired after a message action, with the announcement.
onCountdownEnd(announcement) => void—Fired once when a countdown reaches zero.
labelstring'Announcements'Accessible name of the region.
classstring—Additional classes merged with the collapse class.
refHTMLElement | null—Bindable reference to the outer section.

Keyboard Interactions

KeyAction
TabMove between the message action and the controls.
Enter / SpaceStep, pause, or dismiss from the control buttons.

Accessibility

  • The bar is a labelled region; with several messages it is a carousel of labelled slides.
  • The live countdown is role="timer" with aria-live="off" and a spoken hours/minutes label.
  • Rotation pauses on hover, focus, or a hidden tab so no message changes under the reader.

Motion

Phase 1 still-state: no animation. Faces swap instantly, the viewport snaps to the face height, countdown digits swap instantly, and dismissal closes at once. Phase 2 wires the rise/blur face swap, the height spring, the digit roll, the pause-ring sweep and the collapse.

Notes for AI

  • Pass an id to remember dismissal in localStorage; clearAnnouncementDismissal(id) forgets it.
  • Rotation pauses itself on hover, focus, hidden tabs and reduced motion — no extra wiring needed.

Source of truth: registry/components/announcement-bar/announcement-bar.tsx