Installation
Install Varsel with your package manager and import the bundled stylesheet once. The package ships its own design tokens, so varsel/styles.css is enough to get the default look.
Install package
pnpm install varselImport styles
@import "varsel/styles.css";Usage
Render VarselToaster near the root of your app so every route shares one toast host. Call toast() with a string for quick feedback or with an object when you need a title, description, action, duration, variant, or callbacks.
<script lang="ts">
import { VarselToaster } from "varsel";
let { children } = $props();
</script>
{@render children?.()}
<VarselToaster />Positions & layout
Toasts default to bottom-center, but each notification can choose any of the six viewport anchors. Stacks are calculated per position, and swipe gestures mirror automatically for the chosen edge.
<script lang="ts">
import { toast } from "varsel";
function showToast() {
toast({
title: "Toast pinned to top-left",
description: "Each anchor keeps its own stack.",
position: "top-left",
});
}
</script>
<button onclick={showToast}>top-left</button>Variants & styling
Use default, success, warning, destructive, or info to match the tone of the event. The bundled CSS is driven by variables for colors, shadows, radius, and easing, so you can override the theme without changing the API.
<script lang="ts">
import { toast } from "varsel";
function showToast() {
toast({
title: "default toast",
description: "Pick the tone that matches the event.",
variant: "default",
});
}
</script>
<button onclick={showToast}>Try default</button>Timing & lifecycle
Varsel auto-dismisses toasts after five seconds by default and pauses while users hover, focus, or swipe the stack. Set duration per toast, use 0 for persistent notifications, and keep the returned id when you need to dismiss a toast later.
<script lang="ts">
import { toast } from "varsel";
function showShortToast() {
toast({
title: "Saved",
description: "Done!",
duration: 1500,
});
}
</script>
<button onclick={showShortToast}>Short toast</button>Actions & callbacks
Add one action button when a toast should let the user respond immediately. onAutoClose and onDismiss run after the exit animation, while showClose: false hides the close button and disables swipe dismissal.
<script lang="ts">
import { toast } from "varsel";
function showActionToast() {
toast({
title: "Email scheduled",
description: "Will send in ten minutes.",
action: {
label: "Undo",
onClick: () => {
console.log("Email cancelled");
},
},
});
}
</script>
<button onclick={showActionToast}>Try the action toast</button>Promises & async
Use toast.promise to keep users informed while an async task is loading, succeeds, or fails. The loading state stays open with a spinner, and each state can provide its own copy, variant, duration, action, and close behavior.
<script lang="ts">
import { toast } from "varsel";
const mockDeploy = () =>
new Promise<string>((resolve) => {
setTimeout(() => {
resolve("Production now serves build #542.");
}, 1200);
});
function runDeployment() {
toast.promise(mockDeploy(), {
loading: {
title: "Deploying build",
description: "Packing assets and running health checks...",
},
success: (message) => ({
title: "Deployment complete",
description: message,
variant: "success",
}),
error: {
title: "Deployment failed",
description: "Something went wrong while talking to the server.",
},
});
}
</script>
<button onclick={runDeployment}>Simulate success</button>Headless & Custom
Use toast.custom when you want Varsel's lifecycle and animations with fully custom markup. Your component receives the toast id, the full toast object, and any componentProps, so it can render and dismiss itself however it needs.
<script lang="ts">
import HeadlessToast from "$lib/components/HeadlessToast.svelte";
import { toast } from "varsel";
function showCustomToast() {
toast.custom(HeadlessToast, {
duration: 100000,
componentProps: {
title: "This is a headless toast",
description:
"You have full control of styles and markup, while still having the animations.",
button: {
label: "Reply",
onClick: () => console.log("Reply clicked"),
},
},
});
}
</script>
<button onclick={showCustomToast}>Render toast</button><script lang="ts">
import { toast as varselToast, type PositionedToast } from "varsel";
type Props = {
id: string;
toast: PositionedToast;
title: string;
description: string;
button: {
label: string;
onClick: () => void;
};
};
let { id, title, description, button }: Props = $props();
</script>
<div
class="mx-auto flex w-full max-w-91 items-center rounded-lg bg-white p-4 shadow-lg ring-1 ring-black/5 dark:bg-zinc-900 dark:ring-white/10"
>
<div class="flex flex-1 items-center">
<div class="w-full">
<p class="text-sm font-medium text-gray-900 dark:text-gray-100">{title}</p>
<p class="mt-1 text-sm text-gray-500 dark:text-gray-400">{description}</p>
</div>
</div>
<div class="ml-5 shrink-0">
<button
class="cursor-pointer rounded bg-indigo-50 px-3 py-1 text-sm font-semibold text-indigo-600 hover:bg-indigo-100 dark:bg-indigo-950/50 dark:text-indigo-400 dark:hover:bg-indigo-900/50"
onclick={() => {
button.onClick();
varselToast.dismiss(id);
}}
>
{button.label}
</button>
</div>
</div>API Reference
The public surface is intentionally small: VarselToaster, toast(), helper methods, and the ToastData object. Configure defaults on the toaster, override behavior per toast, and use returned ids with toast.dismiss or toast.dismissAll when you need manual control.
VarselToaster props
| Prop | Type | Default | Description |
|---|---|---|---|
| position | ToastPosition | bottom-center | Default position for all toasts. |
| visibleToasts | number | 3 | Maximum number of toasts visible in the stack at once. |
| expand | boolean | true | Whether the toast stack expands when hovered. |
| duration | number | 5000 | Default duration in milliseconds before a toast automatically closes. |
| closeButton | boolean | true | Whether to show the close button on toasts by default. |
| pauseOnHover | boolean | true | Whether to pause the auto-close timer while hovering over the toast. |
| offset | numberstring | undefined | Distance from the edge of the viewport. |
| dir | ltrrtlauto | auto | Text direction for accessibility and layout. |
| expandedGap | number | 12 | Vertical gap in pixels between toasts when the stack is expanded. |
toast() methods
| Method | Signature | Description |
|---|---|---|
toast | (data: string | ToastInput) => string | Creates a default toast and returns its id. Pass a stable id on the payload to upsert an existing toast in place. |
toast.success | (data: string | ToastVariantInput) => string | Creates a success variant toast. |
toast.warning | (data: string | ToastVariantInput) => string | Creates a warning variant toast. |
toast.error | (data: string | ToastVariantInput) => string | Creates a destructive variant toast. |
toast.info | (data: string | ToastVariantInput) => string | Creates an info variant toast. |
toast.promise | (promise: Promise<T>, options: ToastPromiseOptions) => Promise<T> | Updates one toast automatically as a promise loads, resolves, or rejects. Returns the underlying promise so callers can await the original value or rejection. |
toast.custom | (component: Component, options?: ToastInput) => string | Renders a custom Svelte component as a toast. |
toast.update | (id: string, data: string | Partial<ToastData>) => void | Refreshes an existing toast in place. Pass a string as shorthand for { description }. |
toast.dismiss | (id: string) => void | Programmatically dismisses a toast by id. |
toast.dismissAll | () => void | Dismisses all active toasts. |
ToastData fields
| Field | Type | Description |
|---|---|---|
| id | string | Optional stable id. When provided and a matching active toast exists, the call updates it in place instead of creating a duplicate. |
| title | string | The main title of the notification. |
| description | string | Detailed message or description. |
| duration | number | Overrides the default duration for this toast; Infinity keeps it open. |
| showClose | boolean | Controls close button visibility and swipe dismissal for this toast. |
| variant | defaultsuccesswarningdestructiveinfo | The visual style of the toast. |
| action | { label: string, onClick: () => void } | Renders an action button. |
| onAutoClose | () => void | Runs after the toast finishes its timer-based exit. |
| onDismiss | () => void | Runs after manual dismissal by button, swipe, toast.dismiss, or toast.dismissAll. |
| position | ToastPosition | Overrides the global position for this toast. |
| priority | lowhigh | Announcement priority for assistive tech. "high" promotes the toast to alertdialog with assertive aria-live and adds a visually-hidden role=alert mirror so screen readers read it immediately. |
| className | string | Additional CSS classes for the toast container. |
| component | Component | Internal custom component rendered by toast.custom. |
| componentProps | Record<string, any> | Props passed to the custom component. |