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.

Configure Theme
Theme
Accent Color
Custom
Gray Family
Appearance
Radius
Scaling
Panel Style
Heading Font
Body Font