Toast Notification System
Architecture and API guide for the SveltyCMS Toast Notification System
On this page
SveltyCMS utilizes a custom, enterprise-grade Toast Notification System built organically using Svelte 5 Runes. It is designed to be highly accessible, responsive, and robust against common web architectural pitfalls, such as navigation interruptions.
🌟 Core Features
-
Store-Driven Reactivity: Relies on a unified singleton
$statefor cross-component stability. -
Responsive Positioning: Dynamically repositions to
bottom-centeron mobile, while allowing granulardesktopandtabletsetups through global responsive configurations or per-toast overrides. -
Smart Queueing: Queues notifications seamlessly with a hard limit (default: 5) to prevent screen pollution, replacing the oldest non-persistent toasts first.
-
Pause-on-Hover: Halts internal progress timers when users hover over notifications.
-
Flash Messaging: Bridges server redirects seamlessly via
sessionStorage. -
Navigation Safety: Intelligently pauses and calculates time diffs during SvelteKit page transitions.
-
Accessibility (WCAG Compliant): Uses
aria-live="polite",role="alert", respectsprefers-reduced-motion, honors RTL structures, and provides high-contrast borders.
🏗️ Architecture
The system involves two primary integration components: the State Store and the Rendering Container.
ToastStore(src/stores/toast.svelte.ts): The centralized state machine that handles all logic, caching, and time management.ToastContainer(src/components/toast-container.svelte): The Svelte UI component rendered universally in the+layout.svelte.
ToastStore Lifecycle
When a notification is dispatched (toast.success()), it generates a unique ID, mounts into the $state queue, and immediately binds an unmanaged window.setTimeout.
During a transition (captured via $app/navigation beforeNavigate), the Store recalculates remaining fractions, clears timeouts entirely, and proxies to session storage. Once afterNavigate triggers, the Store rehydrates the queue natively.
📚 General Usage
Toasts are triggered by importing the toast singleton into your components or scripts.
import { toast } from "@src/stores/toast.svelte.ts";
// 1. Basic Messages
toast.success("Settings saved successfully!");
toast.error("Connection timeout.");
toast.warning("Storage limit approaching.");
toast.info("New updates available.");
// 2. Complex Configurations
toast.info({
title: "Update Required",
message: "Please restart the application.",
duration: 10000,
position: "top-center",
action: {
label: "Restart Now",
onClick: () => restartApp(),
},
});
// 3. Persistent Notifications (Manual Dismissal Required)
toast.warning({
title: "Sync Offline",
message: "Background sync is currently disabled.",
duration: Infinity,
persistent: true,
});
🔄 Promise Handling
The toast system supports automated asynchronous promise resolving. It displays a loading notification while waiting for the promise queue, and triggers corresponding success or error messages upon fulfillment.
import { toast } from "@src/stores/toast.svelte.ts";
async function updateProfile() {
const request = fetch("/api/user/profile", { method: "POST" });
await toast.promise(request, {
loading: "Updating profile...",
// Triggered natively when promise fulfills
success: "Profile has been updated!",
// Triggered automatically if promise rejects/throws error
error: (err) => `Update failed: ${err.message}`,
});
}
⚡ Form Actions & Flash Messages
When utilizing SvelteKit Form Actions that result in a navigation redirect, standard toasts will vanish as the page reloads.
SveltyCMS resolves this through Flash Messages.
// Example: src/routes/login/+page.server.ts
import { redirect } from "@sveltejs/kit";
import { toast } from "@src/stores/toast.svelte.ts";
export const actions = {
default: async () => {
// ... internal logic
// Inform the user in the upcoming tick
toast.flash({
type: "success",
message: "Log in successful.",
});
throw redirect(303, "/dashboard");
},
};
Upon resolving /dashboard, the Root Layout invokes toast.checkFlash(), reading out transient data generated by the pre-navigation flash queue.
♿ Accessibility Considerations
- Keyboard Focus: Notification dismissal buttons are natively focusable. Internal actions do not steal focus arbitrarily unless invoked intentionally via Tab targeting.
- RTL Integrity: Automatically inverts transition directions for
flyandslideendpoints whendir="rtl"is inferred. - Visuals: Honors
prefers-contrast: highwith explicit borders, and bypasses animated timers onprefers-reduced-motionprofiles.