Recipes
Copy-ready patterns for the things toasts are actually used for. Each one has a live demo.
Success, error and actions
The island expands to show the description and button, then collapses before it dismisses. A button click dismisses the toast.
dynaura.error({
title: "Payment failed",
description: "Card ending 4242 was declined.",
button: { title: "Retry", onClick: retry },
});Promises
The same island morphs from loading to success or error. success and error can be strings, option objects, or functions of the result. The original promise is returned.
dynaura.promise(save(), {
loading: "Saving...",
success: (data) => ({ title: "Saved", description: `Version ${data.v}` }),
error: { title: "Failed", description: "Check your connection." },
});Progress
Create a sticky loading toast, then patch it with dynaura.update. Frequent progress updates do not restart the toast. Pass progress: undefined to clear the bar.
const id = dynaura.loading({ title: "Uploading", progress: 0 });
onProgress((p) => dynaura.update(id, { progress: p })); // 0 to 1
dynaura.update(id, {
type: "success",
title: "Upload complete",
progress: undefined, // clear the bar
duration: 4000,
confetti: true,
});Live activities
Sticky toasts with a running timer by default, or an animated waveform with kind: "wave".
dynaura.live({
title: "Recording voice memo",
button: { title: "Stop", onClick: stop },
});
dynaura.live({ title: "Now playing", kind: "wave" }); // waveform instead of a timerRich cards
variant: "card" makes a header tab plus any custom body, joined by a curved notch. Card content inherits colors through var(--dynaura-fg), var(--dynaura-muted) and var(--state), so it follows any theme. The header tab follows position: centered for top and bottom, flush to the edge for -left and -right.
dynaura.info({
title: "Boarding soon",
trailing: "40 min",
variant: "card",
duration: 9000,
description: <BoardingPass />, // any React node (a DOM Node in Vue, Svelte and vanilla)
button: { title: "Show boarding pass", onClick: openPass },
});Queue
Show toasts one after another instead of replacing the current one. Set it on the Toaster, or per toast.
// every toast waits its turn
<Toaster queue />
// or per toast
dynaura.info({ title: "Invite sent to Maya", queue: true, duration: 1600 });Custom icons and slots
icon replaces the built-in icon. trailing is a small right-side slot.
import { CalendarDaysIcon } from "@heroicons/react/24/outline";
dynaura.info({
title: "Design sync starts soon",
icon: <CalendarDaysIcon width={16} height={16} />, // replaces the built-in icon
trailing: "5 min", // small right-side slot
});Sticky, update and dismiss
duration: null keeps a toast open. Every call returns an id, so you can patch it with update (including its type) or remove it with dismiss(id). dismiss() with no id closes the current toast, and clear() removes everything including the queue.
const id = dynaura.info({ title: "Sticky until dismissed", duration: null });
dynaura.dismiss(id); // one toast
dynaura.dismiss(); // the current toast, then the next queued one shows
dynaura.clear(); // everything
const sync = dynaura.loading({ title: "Syncing" });
dynaura.update(sync, { type: "success", title: "Synced", duration: 3500 });Positions
Six positions: top, top-left, top-right, bottom, bottom-left and bottom-right. Safe-area insets are added to offset. This changes the island on this page, so reload to reset it.
<Toaster position="bottom-right" offset={16} />