@pithagon/live-region
v0.1.0
Published
A custom element for making announcements with live regions - Svelte 5
Maintainers
Readme
@pithagon/live-region
A Svelte 5 component for making announcements with ARIA live regions
Overview
@pithagon/live-region provides an accessible way to announce dynamic content changes to screen reader users in Svelte 5 applications. It implements ARIA live regions following best practices for web accessibility.
Features
- ✅ Svelte 5 Native - Built with Svelte 5 runes ($state, $effect)
- ✅ Accessible - Follows ARIA live region best practices
- ✅ TypeScript - Full type safety with TypeScript
- ✅ Flexible - Global announcements or component-level usage
- ✅ Smart Queuing - Priority-based message queue (assertive > polite)
- ✅ Cancelable - Cancel delayed announcements when needed
- ✅ Zero Dependencies - Minimal footprint
Installation
# Using npm
npm install @pithagon/live-region
# Using bun
bun add @pithagon/live-region
# Using pnpm
pnpm add @pithagon/live-regionQuick Start
1. Set up the global LiveRegion
Add the LiveRegion component to your root layout (e.g., src/routes/+layout.svelte):
<script>
import { LiveRegion, registerLiveRegion } from '@pithagon/live-region';
let liveRegion;
$effect(() => {
if (liveRegion) {
registerLiveRegion(liveRegion);
}
});
</script>
<LiveRegion bind:this={liveRegion} />
<slot />2. Make announcements
Now you can use the global announce() function anywhere in your app:
<script>
import { announce } from '@pithagon/live-region';
function handleSubmit() {
// ... form submission logic
announce('Form submitted successfully!');
}
</script>
<button onclick={handleSubmit}>Submit</button>Usage
Basic Announcements
import { announce } from '@pithagon/live-region';
// Simple announcement (polite by default)
announce('Item added to cart');
// Polite announcement (doesn't interrupt)
announce('Form saved successfully', {
politeness: 'polite'
});
// Assertive announcement (interrupts screen reader)
announce('Error: Connection lost', {
politeness: 'assertive'
});Delayed Announcements
import { announce } from '@pithagon/live-region';
// Announce after 5 seconds
announce('Your session will expire soon', {
politeness: 'polite',
delayMs: 5000
});Canceling Announcements
import { announce } from '@pithagon/live-region';
// Create a cancelable announcement
const cancelable = announce('Saving changes...', {
delayMs: 3000
});
// Cancel if needed (e.g., save completed early)
cancelable.cancel();Announcing from Elements
import { announceFromElement } from '@pithagon/live-region';
const statusElement = document.getElementById('status');
// Uses aria-label if present, otherwise innerText/textContent
announceFromElement(statusElement);Clearing All Announcements
import { clear } from '@pithagon/live-region';
// Clear all pending announcements (useful for route transitions)
clear();Component-Level Usage
If you prefer not to use global registration:
<script>
import { LiveRegion } from '@pithagon/live-region';
let liveRegion;
function handleClick() {
liveRegion?.announce('Button clicked!');
}
</script>
<LiveRegion bind:this={liveRegion} />
<button onclick={handleClick}>Click me</button>API Reference
Components
LiveRegion
The main component that creates ARIA live region containers.
Props:
delay?: number- Delay between announcements in milliseconds (default: 150)
Methods:
announce(message: string, options?: AnnounceOptions): Cancelable<Promise<void>>announceFromElement(element: HTMLElement, options?: AnnounceOptions): Cancelable<Promise<void>>clear(): void- Clear all pending messagesgetMessage(politeness?: 'polite' | 'assertive'): string- Get current message
Functions
announce(message, options?)
Announce a message using the global live region.
Parameters:
message: string- The message to announceoptions?: AnnounceOptions- Announcement options
Returns: Cancelable<Promise<void>>
announceFromElement(element, options?)
Announce the text content of an element.
Parameters:
element: HTMLElement- The element to announce fromoptions?: AnnounceOptions- Announcement options
Returns: Cancelable<Promise<void>>
registerLiveRegion(instance)
Register a LiveRegion instance as the global live region.
Parameters:
instance: LiveRegion- The LiveRegion component instance
unregisterLiveRegion()
Unregister the current global live region.
clear()
Clear all pending announcements from the global live region.
getMessage(politeness?)
Get the current message from the global live region.
Parameters:
politeness?: 'polite' | 'assertive'- The politeness level (default: 'polite')
Returns: string
Types
type Politeness = 'polite' | 'assertive';
type AnnounceOptions =
| {
politeness?: 'assertive';
delayMs?: never;
}
| {
politeness?: 'polite';
delayMs?: number;
};
type Cancelable<T> = T & {
cancel: () => void;
};Best Practices
1. Use One Global LiveRegion
Place the <LiveRegion /> component in your root layout to ensure it's available across all pages:
<!-- src/routes/+layout.svelte -->
<script>
import { LiveRegion, registerLiveRegion } from '@pithagon/live-region';
let liveRegion;
$effect(() => {
if (liveRegion) {
registerLiveRegion(liveRegion);
}
});
</script>
<LiveRegion bind:this={liveRegion} />
<slot />2. Choose Appropriate Politeness Levels
Use
polite(default) for most announcements:- Form submissions
- Item added to cart
- Content loaded
- Search results updated
Use
assertiveonly for critical, time-sensitive messages:- Fatal errors
- Connection lost
- Security warnings
- Session expiration
3. Keep Messages Concise
Screen readers will read the entire message. Keep announcements brief and clear:
// Good ✅
announce('3 items added to cart');
// Avoid ❌
announce(
'The following items have been successfully added to your shopping cart and you can now proceed to checkout if you wish: Item 1, Item 2, Item 3'
);4. Clean Up on Route Changes
Clear pending announcements when navigating to prevent outdated messages:
<!-- src/routes/+layout.svelte -->
<script>
import { clear } from '@pithagon/live-region';
import { beforeNavigate } from '$app/navigation';
beforeNavigate(() => {
clear();
});
</script>5. Test with Screen Readers
Always test your announcements with actual screen readers:
- macOS: VoiceOver
- Windows: NVDA or JAWS
- Mobile: VoiceOver (iOS) or TalkBack (Android)
Accessibility
This component follows ARIA live region specifications:
- ✅ Uses
aria-live="polite"andaria-live="assertive"attributes - ✅ Uses
aria-atomic="true"to ensure complete messages are read - ✅ Visually hidden but accessible to assistive technologies
- ✅ Implements message queuing to prevent dropped announcements
- ✅ Priority-based queue (assertive messages take precedence)
Examples
See EXAMPLES.md for more detailed usage examples.
Contributing
Contributions are welcome! Please read our Contributing Guide for details on our code of conduct and the process for submitting pull requests.
License
MIT © Pithagon
Related Packages
- @pithagon/components - Accessible Svelte 5 components
- @pithagon/behaviors - Behavioral utilities for Svelte
- @pithagon/utils - Common utilities
