Loading...
Loading...
Guide to Sonner, the React toast library — install and wire up the Toaster, pick the right toast() call, promise and loading toasts, updating, dismissing and persisting toasts, styling, theming and icons, positioning and multiple toasters. Use when working with Sonner or troubleshooting it — toasts that don't appear, appear twice, lose their styles, ignore Tailwind classes, sit behind a modal, or don't follow dark mode.
npx skill4agent add emilkowalski/skills ask-sonner<Toaster />toast()<Toaster />layout.tsxtoast()toast()import { Toaster } from 'sonner'; // once, in layout
import { toast } from 'sonner'; // anywhere client-side| You want | Call |
|---|---|
| Plain message | |
| Success / error / info / warning icon | |
| Spinner while you manage state yourself | |
| Loading → success/error tied to a promise | |
| Button that does something | |
| Custom JSX, default toast shell | |
| Custom JSX, no styles at all | |
toast()idtoast.success(…, { id })toast.promiseconst id = toast.loading('Uploading…');
toast.success('Uploaded', { id });{ duration: Infinity }toast.dismiss(id)toast.dismiss()useSonner()toast.getActiveToasts()toast(() => <a href="…">View</a>)idtoast('…', { toasterId: 'canvas' })toasterIdonDismissonAutoCloserichColorsinverttoastOptions={{ style: {…} }}styletoast()toastOptions={{ classNames: { toast, title, description, actionButton, cancelButton, closeButton } }}!important!text-red-900toast.custom()toast()unstyled: trueiconsiconnulltheme'light'theme="system"<Toaster theme={resolvedTheme} />next-themes| Symptom | Cause → fix |
|---|---|
| Toast never appears | No |
| Same toast appears twice | Two Toasters mounted (layout and page) — keep one. Or |
| Tailwind/CSS classes have no effect | Default styles override them. Mark them |
| Toasts render completely unstyled (common in Astro, view transitions) | Sonner's injected stylesheet was lost — import it explicitly in a layout: |
| Unstyled inside Shadow DOM | Styles land in |
| Toast behind a modal/overlay, or clipped | An ancestor creates a stacking context ( |
| Dark mode ignored | |
| Success/error look gray, not green/red | That's the default. Add |
| Toast never closes | |
| It needs a promise (or a function returning one) as its first argument, and the promise must actually resolve/reject. |
| Swipe-to-dismiss goes the wrong way / doesn't work | Directions derive from |
| Toast shows up in every toaster | Multiple toasters need targeting: give each Toaster an |
| Toasts too close to the screen edge on mobile | |