Toast
A non-intrusive notification popup with auto-dismiss, action buttons, and swipe-to-dismiss. Built on Radix Toast.
Preview
Import
import { Toaster, toast } from "@sigil-ui/components";Setup
Add <Toaster /> to your root layout:
<Toaster />Usage
"use client";
import { useState } from "react";
import { Button, Sonner, Toaster, ToastPromise, sonnerToast, toast } from "@sigil-ui/components";
const TRAFFIC = [
{ month: "Apr", desktop: 186, mobile: 80 },
{ month: "May", desktop: 224, mobile: 112 },
{ month: "Jun", desktop: 208, mobile: 132 },
{ month: "Jul", desktop: 278, mobile: 166 },
{ month: "Aug", desktop: 305, mobile: 184 },
{ month: "Sep", desktop: 342, mobile: 218 },
];
function ToastPreview({ engine = "radix" }: { engine?: "radix" | "sonner" | "promise" }) {
const [pending, setPending] = useState(false);
async function save(fail = false) {
setPending(true);
const request = new Promise<void>((resolve, reject) => {
window.setTimeout(() => fail ? reject(new Error("Demo request failed")) : resolve(), 800);
});
try {
await ToastPromise(request, { loading: "Saving project…", success: "Project saved", error: "Could not save. Try again." });
} catch {
// The toast displays the demo failure; keep the button available for retry.
} finally { setPending(false); }
}
return (
<div className="grid gap-[var(--s-space-16)] w-full">
{engine === "radix" ? <Toaster position="top-right" /> : <Sonner position="top-right" closeButton />}
<div className="flex flex-wrap gap-[var(--s-space-12)]">
{engine === "promise" ? <>
<Button disabled={pending} onClick={() => save()}>Save project</Button>
<Button variant="outline" disabled={pending} onClick={() => save(true)}>Try a failed request</Button>
</> : <>
<Button onClick={() => engine === "sonner" ? sonnerToast.success("Project saved", { description: "Your changes are ready." }) : toast({ title: "Project saved", description: "Your changes are ready.", variant: "success" })}>Show success</Button>
<Button variant="outline" onClick={() => engine === "sonner" ? sonnerToast.error("Could not save", { description: "Check your connection and try again." }) : toast({ title: "Could not save", description: "Check your connection and try again.", variant: "error" })}>Show error</Button>
</>}
</div>
<p className="text-[var(--s-text-muted)] text-[length:var(--s-size-sm)]">Notifications appear in the top right. Dismiss them with the close button.</p>
</div>
);
}Variants
toast.success("File uploaded.");
toast.error("Something went wrong.");
toast.warning("Storage almost full.");
toast.info("New version available.");With action
toast("Message deleted.", {
action: { label: "Undo", onClick: () => restore() },
});With description
toast("Deployment complete", {
description: "Your changes are now live in production.",
});Custom duration
toast("Quick flash", { duration: 2000 });
toast("Sticky notice", { duration: Infinity });Token integration
| CSS Variable | Used for |
|---|---|
--s-surface | Toast background |
--s-text | Toast message color |
--s-text-muted | Description color |
--s-border | Toast border |
--s-success | Success variant accent |
--s-error | Error variant accent |
--s-warning | Warning variant accent |
--s-card-radius | Border radius |
--s-shadow-lg | Toast elevation |
--s-duration-normal | Enter/exit animation |
Props
toast()
| Param | Type | Default | Description |
|---|---|---|---|
message | string | — | Toast message |
options.description | string | — | Secondary text |
options.action | { label: string; onClick: () => void } | — | Action button |
options.duration | number | 5000 | Auto-dismiss time in ms |
Toaster
| Prop | Type | Default | Description |
|---|---|---|---|
position | "top-right" | "top-left" | "bottom-right" | "bottom-left" | "bottom-right" | Toast position |
className | string | — | Additional CSS classes |
Accessibility
- Uses
role="status"witharia-live="polite"for non-urgent toasts - Error toasts use
aria-live="assertive" - Swipe-to-dismiss works on touch devices
- Focus moves to action button when present