thc-toast-conext-api Svelte Themes

Thc Toast Conext Api

A lightweight, accessible toast notification system built for Svelte 5 using the Context API pattern

Toast with Context API — Svelte 5 Demo

A lightweight, accessible toast notification system built for Svelte 5 using the Context API pattern. This interactive demo showcases dynamic position switching and all toast variants.

Features

  • Context API Pattern — Access toast functions anywhere in your component tree without prop drilling
  • Dynamic Positioning — Switch between 6 positions at runtime (top-left, top-center, top-right, bottom-left, bottom-center, bottom-right)
  • 4 Toast Types — Info, success, warning, and error variants
  • Auto-dismiss — Configurable duration with manual dismiss option
  • Accessible — ARIA live regions, proper roles, and keyboard support
  • TypeScript — Full type safety with exported interfaces
  • Zero Dependencies — Lightweight implementation using only Svelte primitives

Quick Start

# Install dependencies
pnpm install

# Start development server
pnpm dev

Project Structure

src/lib/components/toast/
├── index.ts                    # Public exports
├── types.ts                    # TypeScript interfaces
├── toast-context.svelte.ts     # Context and state management
├── ToastProvider.svelte        # Provider component
├── ToastViewport.svelte        # Renders toast collection
└── ToastItem.svelte            # Individual toast component

Static vs Dynamic Position

This demo extends the base toast system to support dynamic position switching. Understanding the difference:

Static Position (Article Implementation)

In the companion article, position is set once on ToastProvider and stored in context:

<!-- Position fixed for app lifetime -->
<ToastProvider position="bottom-right">
    {@render children()}
    <ToastViewport />
</ToastProvider>

The ToastViewport reads position from context via getToastPosition(). This is simpler and sufficient for most applications.

Dynamic Position (This Demo)

For runtime position changes, we:

  1. Added a position prop to ToastViewport that overrides context
  2. Created a separate context for position control in the layout
  3. Pass position directly to ToastViewport for reactive updates
<!-- +layout.svelte -->
<script lang="ts">
    let currentPosition = $state<ToastPosition>('top-right');

    // Expose setter via context for child components
    setContext('toast-position-control', {
        get position() {
            return currentPosition;
        },
        setPosition: (pos) => {
            currentPosition = pos;
        }
    });
</script>

<ToastProvider defaultDuration={5000} maxToasts={5}>
    {@render children()}

    <!-- Position prop enables reactive updates -->
    <ToastViewport position={currentPosition} />
</ToastProvider>

Why this works: ToastProvider uses untrack() which only captures initial values. The ToastViewport position prop is reactive via $derived(positionProp ?? contextPosition).

Use Case Where to set position
Static (never changes) ToastProvider
Dynamic (user can change) ToastViewport prop

Usage

Basic Usage

<script lang="ts">
    import { getToastContext } from '$lib/components/toast';

    const toast = getToastContext();
</script>

<button onclick={() => toast.success('Saved!')}> Save </button>

All Toast Methods

// Convenience methods
toast.info('Information message');
toast.success('Operation completed!');
toast.warning('Check your input', 10000); // custom duration
toast.error('Something went wrong');

// Full options API
const id = toast.show({
    message: 'Custom toast',
    type: 'info',
    duration: 0 // 0 = no auto-dismiss
});

// Programmatic dismiss
toast.dismiss(id);
toast.dismissAll();

Provider Configuration

<ToastProvider
  defaultDuration={5000}  <!-- Auto-dismiss time in ms -->
  maxToasts={5}           <!-- Maximum visible toasts -->
  position="bottom-right" <!-- Initial position (static mode) -->
>

API Reference

ToastContext

Method Description
toast.info(message, duration?) Show info toast
toast.success(message, duration?) Show success toast
toast.warning(message, duration?) Show warning toast
toast.error(message, duration?) Show error toast
toast.show(options) Show toast with full options
toast.dismiss(id) Dismiss specific toast
toast.dismissAll() Dismiss all toasts
toast.toasts Read-only array of active toasts

ToastPosition

type ToastPosition =
    | 'top-right'
    | 'top-left'
    | 'top-center'
    | 'bottom-right'
    | 'bottom-left'
    | 'bottom-center';

Architecture Highlights

  • Class-based state manager — Encapsulates reactive state and timer registry
  • Symbol context keys — Prevents accidental key collisions
  • Effect cleanup — Timers cleared on provider unmount
  • Readonly exportstoasts array is immutable to consumers

Acknowledgments

  • Built as a companion demo for The Hackpile Chronicles article on Svelte 5's Context API and Compound Components pattern
  • Thanks to the Svelte team for their excellent tools and documentation

Contributing

This is a demo project, but feel free to fork and customize for your needs!

License

MIT


Built with ❤️ using Svelte 5 and SvelteKit

Top categories

Loading Svelte Themes