Tiny, headless accessibility toolkit for Svelte/SvelteKit: dual aria-live regions, imperative announce() API, screen-reader utility components, and a route-change helper.
polite & assertive) to avoid priority clashesannounce(text, options?) API with: politeness, priority sorting, TTL auto-cleanup, optional dedupeKey<LiveAnnouncer /> component – inject once near root<VisuallyHidden /> wrapper for SR-only text<SkipTo /> accessible skip link with safe focus managementannounceRouteChange() helper for SvelteKit navigation events.d.ts typespnpm add svelte-aria-live
# or
npm install svelte-aria-live
Add the announcer once (e.g. in App.svelte or layout):
<script>
import { LiveAnnouncer } from 'svelte-aria-live';
</script>
<LiveAnnouncer />
import { announce } from "svelte-aria-live";
announce("Saved successfully");
announce("Error saving", { politeness: "assertive", priority: 100 });
announce("Loading data…", { dedupeKey: "loading", ttlMs: 3000 });
import { announceRouteChange } from "svelte-aria-live";
// After navigation:
announceRouteChange(() => document.title);
<SkipTo target="#main" />
<main id="main">...</main>
<h1>Dashboard <VisuallyHidden>(real-time metrics)</VisuallyHidden></h1>
announce(text: string, options?: AnnounceOptions)Adds an announcement to the queue. Returns numeric id.
AnnounceOptions:
politeness: 'polite' | 'assertive' (default 'polite')priority: number (higher renders first; default 0)ttlMs: milliseconds before removal (default 5000)dedupeKey: string; replaces any prior announcements with same keyannounceRouteChange(getTitle?: () => string, opts?)Announces a route change assertively with high priority (200) and dedupe key 'route'.
<LiveAnnouncer limit={5} />Renders two off-screen regions. limit trims visible DOM nodes (older messages still removed by TTL).
<VisuallyHidden />Wrap SR-only content. Pure headless styling.
<SkipTo target="#main" />Skip link focusing target. Temporarily sets tabindex="-1" if necessary for focus.
Off-screen pattern uses both classic clip: rect(0 0 0 0) and modern clip-path: inset(50%) for broad compatibility.
Two separate live regions prevent assertive announcements from starving polite messages.
No aria-atomic set to allow incremental updates.
pnpm install
pnpm check
pnpm build
Outputs package/index.js + index.d.ts.
pnpm dev:demo
# build/preview
pnpm build:demo
pnpm preview:demo
Open http://localhost:5173 and trigger buttons; inspect DOM to see live regions update.
MIT © 2025 Nickbrit