npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

sileo-svelte

v0.0.5

Published

Physics-based gooey toast notifications for Svelte 5

Readme

sileo-svelte

Physics-based toast notifications for Svelte 5.

Unofficial Svelte 5 port of Sileo by Aaryan.

Installation

npm install sileo-svelte

Quick Start

1. Mount the toaster once

<!-- src/routes/+layout.svelte -->
<script>
    import { Toaster } from 'sileo-svelte';
    import 'sileo-svelte/styles.css';

    let { children } = $props();
</script>

{@render children()}

<Toaster position="top-right" />

2. Trigger toasts from anywhere

<script>
    import { sileo } from 'sileo-svelte';
</script>

<button onclick={() => sileo.success('Saved', 'Your changes have been saved.')}>Save</button>

<Toaster /> Props

Only one <Toaster /> is needed in your app.

| Prop | Type | Default | Description | | ---------- | --------------------------------------- | ------------- | ----------------------------------------------------------------------------------------------- | | position | SileoPosition | 'top-right' | Default viewport for new toasts. Per-toast position still overrides this. | | offset | number \| string \| SileoOffsetConfig | undefined | Offset from screen edges. Number values are treated as px. | | options | Partial<SileoOptions> | undefined | Global defaults merged into every toast call. Per-toast fields win. classes and styles are merged per-key. | | children | Snippet | undefined | Optional content rendered before toast viewports. |

SileoOffsetConfig:

type SileoOffsetConfig = Partial<{
    top: number | string;
    right: number | string;
    bottom: number | string;
    left: number | string;
}>;

SileoPosition:

'top-left' | 'top-center' | 'top-right' | 'bottom-left' | 'bottom-center' | 'bottom-right';

sileo API

All creation methods return the toast id: string.

Creation methods

show(input: SileoInput, description?: SileoOptions['description']): string
success(input: SileoInput, description?: SileoOptions['description']): string
error(input: SileoInput, description?: SileoOptions['description']): string
warning(input: SileoInput, description?: SileoOptions['description']): string
info(input: SileoInput, description?: SileoOptions['description']): string
action(input: SileoInput, description?: SileoOptions['description']): string
loading(input: SileoInput, description?: SileoOptions['description']): string

SileoInput:

type SileoInput = SileoOptions | string;

Examples:

sileo.success({ title: 'Saved' });
sileo.success('Saved');
sileo.success('Saved', 'Your changes have been saved.');

// loading defaults to duration: null unless explicitly provided
const id = sileo.loading('Uploading...');
sileo.update(id, { state: 'success', title: 'Uploaded' });

Scoped defaults

Use sileo.with(defaults) to avoid repeating common options.

const billingToasts = sileo.with({
    position: 'bottom-right',
    duration: 4000,
    fill: '#121212'
});

billingToasts.success('Invoice paid');
billingToasts.error('Payment failed', 'Please retry with another card.');

Defaults are merged recursively for classes and styles, and shallow-merged for other fields.

Promise helper

promise<T>(
  promise: Promise<T> | (() => Promise<T>),
  opts: SileoPromiseOptions<T>
): Promise<T>
sileo.promise(() => fetch('/api/upload', { method: 'POST' }), {
    loading: { title: 'Uploading' },
    success: () => ({ title: 'Done', description: 'File uploaded successfully!' }),
    error: (err) => ({
        title: 'Failed',
        description: err instanceof Error ? err.message : 'Upload failed.'
    })
});

SileoPromiseOptions<T>:

| Option | Type | Required | Description | | ---------- | -------------------------------------------------- | -------- | --------------------------------------------------------- | | id | string | No | Existing toast id to morph instead of creating a new one. | | loading | Pick<SileoOptions, 'title' \| 'icon'> | Yes | Pending state content. | | success | SileoOptions \| ((data: T) => SileoOptions) | Yes | Success state content. | | error | SileoOptions \| ((err: unknown) => SileoOptions) | Yes | Error state content. | | action | SileoOptions \| ((data: T) => SileoOptions) | No | If provided, replaces success state. | | position | SileoPosition | No | Position override for the promise toast. |

Update and dismissal

update(id: string, opts: SileoOptions & { state?: SileoState }): void
dismiss(id: string): void
close(id: string): void
clear(position?: SileoPosition): void
  • update: morphs content/state in place.
  • dismiss: immediate exit animation.
  • close: collapse first, then exit.
  • clear: remove all toasts (or a specific viewport).

SileoOptions

| Field | Type | Default | Description | | ------------- | --------------------------------------------------- | ------------------ | ------------------------------------------------------- | | title | string | State name | Header title. | | description | string \| Snippet | undefined | Expanded body content. | | position | SileoPosition | Toaster position | Per-toast viewport override. | | duration | number \| null | 6000 | Auto-dismiss timeout in ms. null keeps it persistent. | | icon | Snippet \| null | State icon | Custom icon snippet; null hides icon. | | classes | SileoClasses | undefined | Per-part class overrides. | | styles | SileoStyles | undefined | Per-toast color variable overrides (Tailwind-free). | | fill | string | '#1c1c1e' | Toast background color. | | roundness | number | 18 | Corner radius. | | autopilot | boolean \| { expand?: number; collapse?: number } | true | Automatic expand/collapse behavior. | | button | SileoButton | undefined | Action button shown in expanded body. |

SileoClasses:

interface SileoClasses {
    title?: string;
    description?: string;
    badge?: string;
    button?: string;
}

SileoStyles:

interface SileoStyles {
    titleColor?: string;
    descriptionColor?: string;
    badgeColor?: string;
    badgeBackground?: string;
    buttonColor?: string;
    buttonBackground?: string;
    buttonHoverBackground?: string;
}

SileoButton:

interface SileoButton {
    title: string;
    onClick: (id: string) => void;
}

SileoState:

'success' | 'loading' | 'error' | 'warning' | 'info' | 'action';

Practical Examples

Custom appearance

sileo.success({ title: 'Dark', description: 'Custom background.', fill: '#1a1a2e' });
sileo.info({ title: 'Square', description: 'Reduced roundness.', roundness: 4 });
sileo.warning({ title: 'Manual', description: 'Hover to read.', autopilot: false });

Styling with classes and styles

// Class-based styling
sileo.action({
    title: 'Class styling',
    description: 'Uses classes.title/classes.description/classes.button',
    classes: {
        title: 'text-foreground',
        description: 'text-foreground',
        button: 'text-primary-foreground hover:bg-primary/90'
    },
    button: { title: 'Close', onClick: (id) => sileo.close(id) }
});

// Variable-based styling (recommended if utility extraction is inconsistent)
sileo.action({
    title: 'Variable styling',
    description: 'Uses styles.*',
    styles: {
        titleColor: 'var(--foreground)',
        descriptionColor: 'var(--foreground)',
        buttonColor: 'var(--primary-foreground)',
        buttonBackground: 'var(--primary)',
        buttonHoverBackground: 'color-mix(in oklch, var(--primary) 85%, black)'
    },
    button: { title: 'Close', onClick: (id) => sileo.close(id) }
});

Tailwind note:

  • If utility classes are passed inside JS strings (like options.classes.button), Tailwind may not always detect them.
  • For Tailwind v4, safelist them via @source inline("text-foreground text-primary-foreground hover:bg-primary/90").

Reusing a toast id

const id = sileo.loading('Uploading file...');

sileo.update(id, { title: 'Uploading', description: '50%' });
sileo.update(id, { state: 'success', title: 'Done', description: '100%', duration: 4000 });

Svelte snippets for rich content (description and icon)

SileoOptions supports snippets in two places:

  • description: rich body content in the expanded area
  • icon: custom header icon badge
<script>
    import { sileo } from 'sileo-svelte';
</script>

{#snippet customDescription()}
    <div>
        <strong>Release ready.</strong>
        <p>Click deploy to roll out v2.4.0.</p>
    </div>
{/snippet}

{#snippet rocketIcon()}
    <svg
        xmlns="http://www.w3.org/2000/svg"
        width="16"
        height="16"
        viewBox="0 0 24 24"
        fill="none"
        stroke="currentColor"
        stroke-width="2"
        stroke-linecap="round"
        stroke-linejoin="round"
        aria-hidden="true"
    >
        <path d="M4.5 16.5c-1.5 1.26-2 3.75-2 3.75s2.49-.5 3.75-2l3-3-1.75-1.75z" />
        <path d="M14 10l-4 4" />
        <path d="M16 4l4 4" />
        <path d="M21.17 2.83a2.83 2.83 0 0 1 0 4L11 17l-4-4L17.17 2.83a2.83 2.83 0 0 1 4 0z" />
    </svg>
{/snippet}

<button
    onclick={() =>
        sileo.action({
            title: 'Deploy',
            description: customDescription,
            icon: rocketIcon,
            button: {
                title: 'Run',
                onClick: (id) => sileo.close(id)
            }
        })}>Show Rich Toast</button
>

Notes:

  • description and icon both accept either plain values (string / null) or snippets.
  • Set icon: null to hide the icon entirely.
  • Snippets are also valid in sileo.update(...) payloads, so you can morph to/from rich content.

Advanced workflows (update + promise orchestration)

const id = sileo.loading('Deploying v2.4.0...');

await delay(1000);
sileo.update(id, {
    state: 'info',
    title: 'Uploading build',
    description: 'Artifacts uploaded to edge cache.'
});

await delay(1000);
sileo.update(id, {
    state: 'warning',
    title: 'Running health checks',
    description: 'Smoke tests on 6 regions...'
});

// Final stage: morph same toast through promise lifecycle
sileo.promise(
    async () => {
        await delay(900);
        return await releaseToProduction();
    },
    {
        id,
        loading: { title: 'Rolling out' },
        success: () => ({
            state: 'action',
            title: 'Deployment complete',
            description: 'Traffic switched to v2.4.0.',
            button: {
                title: 'View logs',
                onClick: (toastId) => {
                    openDeploymentLogs();
                    sileo.close(toastId);
                }
            }
        }),
        error: (err) => ({
            title: 'Rollback triggered',
            description: err instanceof Error ? err.message : 'Unknown deploy error',
            duration: null
        })
    }
);
// Action-first flow that morphs into promise states
sileo.action({
    title: 'Update available',
    description: 'Version 2.0 is ready to install.',
    button: {
        title: 'Install now',
        onClick: (id) => {
            sileo.promise(() => installUpdate(), {
                id,
                loading: { title: 'Installing' },
                success: () => ({
                    state: 'action',
                    title: 'Installed successfully',
                    description: 'Restart app to apply the update.',
                    button: {
                        title: 'Restart',
                        onClick: (toastId) => sileo.close(toastId)
                    }
                }),
                error: (err) => ({
                    state: 'action',
                    title: 'Install failed',
                    description: err instanceof Error ? err.message : 'Unknown install error',
                    duration: null,
                    button: {
                        title: 'Retry',
                        onClick: (toastId) => {
                            sileo.promise(() => installUpdate(), {
                                id: toastId,
                                loading: { title: 'Retrying install' },
                                success: { title: 'Retry succeeded', description: 'Update installed.' },
                                error: { title: 'Still failing', description: 'Please check logs.', duration: null }
                            });
                        }
                    }
                })
            });
        }
    }
});

Toaster defaults and viewport offset

<Toaster
    position="bottom-right"
    options={{
        duration: 4000,
        fill: '#0a0a0a',
        roundness: 12
    }}
    offset={{ top: 60, right: 16 }}
/>

Exports

import {
    Toaster,
    sileo,
    type SileoApi,
    type SileoScopedApi,
    type SileoInput,
    type SileoOptions,
    type SileoPosition,
    type SileoState,
    type SileoClasses,
    type SileoStyles,
    type SileoButton,
    type SileoPromiseOptions
} from 'sileo-svelte';

Import CSS separately:

import 'sileo-svelte/styles.css';

CSS Customization

Override these variables globally:

:root {
    --sileo-duration: 600ms;
    --sileo-height: 40px;
    --sileo-width: 350px;

    --sileo-state-success: oklch(0.723 0.219 142.136);
    --sileo-state-loading: oklch(0.75 0 0);
    --sileo-state-error: oklch(0.637 0.237 25.331);
    --sileo-state-warning: oklch(0.795 0.184 86.047);
    --sileo-state-info: oklch(0.685 0.169 237.323);
    --sileo-state-action: oklch(0.623 0.214 259.815);
}

Per-toast variables set via options.styles map to these CSS vars on each toast root:

  • --sileo-title-color
  • --sileo-description-color
  • --sileo-badge-color
  • --sileo-badge-bg
  • --sileo-button-color
  • --sileo-button-bg
  • --sileo-button-bg-hover

Credits

License

MIT