Skip to content

Documentation

Toast Notification System

Architecture and API guide for the SveltyCMS Toast Notification System

3/27/2026
3 min read Edit on GitHub

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 $state for cross-component stability.

  • Responsive Positioning: Dynamically repositions to bottom-center on mobile, while allowing granular desktop and tablet setups 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", respects prefers-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.

  1. ToastStore (src/stores/toast.svelte.ts): The centralized state machine that handles all logic, caching, and time management.
  2. 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 fly and slide endpoints when dir="rtl" is inferred.
  • Visuals: Honors prefers-contrast: high with explicit borders, and bypasses animated timers on prefers-reduced-motion profiles.

Related

architectureuinotificationssvelte5
Was this page helpful?