Sonner (Toast)
Non-blocking floating notification system with swipe-to-dismiss, hover expansion, and promise lifecycle helpers.
// Plain markup
import { ToastProvider } from "@shavin/ui";Setup
Mount <ToastProvider> once near the app root (set a default position and duration), then call useToast() anywhere. Toasts stack, expand on hover, and swipe left/right to dismiss.
<ToastProvider position="bottom-right" duration={4000}>{children}</ToastProvider>
const t = useToast();
t.success("Saved");Positions — click a cell to move the toaster and fire a toast
<ToastProvider position="top-center">…</ToastProvider>Types — trigger several to see them stack
const t = useToast();
t.toast("Default message");
t.success("Changes saved");
t.error("Something went wrong");
t.warning("Storage almost full");
t.info("A new version is available");Description, action & custom duration
t.success("Payment received", {
description: "Your invoice 1024 has been marked paid.",
duration: 8000, // ms — overrides the provider default
});
t.toast("Message archived", {
action: { label: "Undo", onClick: () => t.success("Restored") },
});Loading & promise
t.promise(saveSettings(), {
loading: "Saving…",
success: "Settings saved",
error: "Could not save",
});Custom content
t.custom(
<div className="flex items-center gap-3">
<img src="/avatar.png" className="h-9 w-9 rounded-full" />
<div>
<div className="text-sm font-medium">Jordan mentioned you</div>
<div className="text-xs text-fg-muted">"can you review the invoice?"</div>
</div>
</div>,
);Props
Toast takes no props beyond className and the native element's attributes.