Shadcn Sonner (Toast)
Free shadcn/ui toast component for React — built on Sonner. Success/error/info/warning, descriptions, action buttons, promise (loading→success/error), rich colors, and fully custom toasts. The toast that replaced the deprecated shadcn Toast.
Installation
{
"registries": {
"@designrevision": "https://registry.designrevision.com/r/{name}.json"
}
}
Add to your existing components.json. Requires shadcn/ui v2.3+.
Packages
Props
No props documented yet.
"use client"
import { useTheme } from "next-themes"
import { Toaster as Sonner, ToasterProps } from "sonner"
const Toaster = ({ ...props }: ToasterProps) => {
const { theme = "system" } = useTheme()
return (
<Sonner
theme={theme as ToasterProps["theme"]}
className="toaster group"
style={
{
"--normal-bg": "var(--popover)",
"--normal-text": "var(--popover-foreground)",
"--normal-border": "var(--border)",
} as React.CSSProperties
}
{...props}
/>
)
}
export { Toaster }
Examples
Sonner
The canonical toast — a button that calls `toast()` with a title and a description.
Packages
Props
No props documented yet.
"use client"
import { toast } from "sonner"
import { Button } from "@/components/ui/button"
import { Toaster } from "@/components/ui/sonner"
export default function SonnerDemo01() {
return (
<div className="flex flex-col items-center gap-4">
<Button
variant="outline"
onClick={() =>
toast("Event has been created", {
description: "Sunday, December 3, 2025 at 9:00 AM",
})
}
>
Show toast
</Button>
{/* Mount <Toaster /> once near the root of your app — shown here per example. */}
<Toaster />
</div>
)
}
Types
Success, error, info, and warning toasts via `toast.success` / `.error` / `.info` / `.warning`.
Packages
Props
No props documented yet.
"use client"
import { toast } from "sonner"
import { Button } from "@/components/ui/button"
import { Toaster } from "@/components/ui/sonner"
export default function SonnerTypes01() {
return (
<div className="flex flex-col items-center gap-4">
<div className="flex flex-wrap items-center justify-center gap-2">
<Button
variant="outline"
size="sm"
onClick={() => toast.success("Changes saved")}
>
Success
</Button>
<Button
variant="outline"
size="sm"
onClick={() => toast.error("Something went wrong")}
>
Error
</Button>
<Button
variant="outline"
size="sm"
onClick={() => toast.info("A new update is available")}
>
Info
</Button>
<Button
variant="outline"
size="sm"
onClick={() => toast.warning("Your trial ends in 3 days")}
>
Warning
</Button>
</div>
<Toaster />
</div>
)
}
With description
A toast with a title and a secondary description line.
Packages
Props
No props documented yet.
"use client"
import { toast } from "sonner"
import { Button } from "@/components/ui/button"
import { Toaster } from "@/components/ui/sonner"
export default function SonnerDescription01() {
return (
<div className="flex flex-col items-center gap-4">
<Button
variant="outline"
onClick={() =>
toast.success("Payment received", {
description: "We've emailed a receipt to [email protected].",
})
}
>
Show toast
</Button>
<Toaster />
</div>
)
}
With action
A toast with an **Undo** action button and a dismiss — the classic undo pattern.
Packages
Props
No props documented yet.
"use client"
import { toast } from "sonner"
import { Button } from "@/components/ui/button"
import { Toaster } from "@/components/ui/sonner"
export default function SonnerAction01() {
return (
<div className="flex flex-col items-center gap-4">
<Button
variant="outline"
onClick={() =>
toast("File moved to trash", {
action: {
label: "Undo",
onClick: () => toast.success("File restored"),
},
cancel: {
label: "Dismiss",
onClick: () => {},
},
})
}
>
Show toast
</Button>
<Toaster />
</div>
)
}
Promise
`toast.promise` ties a toast to an async request — loading, then success or error.
Packages
Props
No props documented yet.
"use client"
import { toast } from "sonner"
import { Button } from "@/components/ui/button"
import { Toaster } from "@/components/ui/sonner"
function uploadFile() {
return new Promise<{ name: string }>((resolve, reject) => {
setTimeout(() => {
if (Math.random() > 0.3) {
resolve({ name: "report.pdf" })
} else {
reject(new Error("Network error"))
}
}, 1500)
})
}
export default function SonnerPromise01() {
return (
<div className="flex flex-col items-center gap-4">
<Button
variant="outline"
onClick={() =>
toast.promise(uploadFile(), {
loading: "Uploading…",
success: (data) => `${data.name} uploaded`,
error: "Upload failed — please try again",
})
}
>
Show toast
</Button>
<Toaster />
</div>
)
}
Rich colors & close
A `
Packages
Props
No props documented yet.
"use client"
import { toast } from "sonner"
import { Button } from "@/components/ui/button"
import { Toaster } from "@/components/ui/sonner"
export default function SonnerRich01() {
return (
<div className="flex flex-col items-center gap-4">
<div className="flex flex-wrap items-center justify-center gap-2">
<Button
variant="outline"
size="sm"
onClick={() => toast.success("Profile updated")}
>
Success
</Button>
<Button
variant="outline"
size="sm"
onClick={() => toast.error("Card declined")}
>
Error
</Button>
<Button
variant="outline"
size="sm"
onClick={() => toast.warning("Storage almost full")}
>
Warning
</Button>
</div>
{/* richColors gives each type a colored surface; closeButton adds an X. */}
<Toaster richColors closeButton />
</div>
)
}
Custom JSX
`toast.custom` renders fully custom content — your own icon, layout, and dismiss button.
Packages
Props
No props documented yet.
"use client"
import { CheckCircle2Icon } from "lucide-react"
import { toast } from "sonner"
import { Button } from "@/components/ui/button"
import { Toaster } from "@/components/ui/sonner"
export default function SonnerCustom01() {
return (
<div className="flex flex-col items-center gap-4">
<Button
variant="outline"
onClick={() =>
toast.custom((id) => (
<div className="bg-popover text-popover-foreground flex w-[340px] items-center gap-3 rounded-md border p-4 shadow-lg">
<CheckCircle2Icon className="size-5 shrink-0 text-emerald-500" />
<div className="flex-1">
<p className="text-sm font-medium">Backup complete</p>
<p className="text-muted-foreground text-xs">
Your workspace was backed up to the cloud.
</p>
</div>
<Button
variant="ghost"
size="sm"
className="-mr-1 h-7"
onClick={() => toast.dismiss(id)}
>
Close
</Button>
</div>
))
}
>
Show toast
</Button>
<Toaster />
</div>
)
}
The Shadcn Sonner is the toast — built on Sonner, the toast library by Emil Kowalski. shadcn deprecated its old Toast component in favour of Sonner, so this is the current, recommended way to show toasts. The examples below cover the whole toast() API: types, descriptions, actions, promises, rich colors, and custom toasts.
Built on Sonner
The shadcn layer is a thin <Toaster /> wrapper over Sonner that themes it to your design tokens (via CSS variables) and follows your light/dark theme. Install it:
npm install sonner
(The shadcn component also pulls in next-themes for theme detection; it falls back to the system theme if you don't use a theme provider.)
Mount the Toaster once
Sonner is API-driven: you mount one <Toaster /> near the root of your app — typically in app/layout.tsx — and then call toast() from anywhere:
// app/layout.tsx
<body>
{children}
<Toaster />
</body>
The examples on this page each render their own Toaster so they work standalone, but your app needs only one.
The toast() API
Call toast from "sonner":
- Basic —
toast("Event has been created", { description: "…" }). - Types —
toast.success(...),toast.error(...),toast.info(...),toast.warning(...)(the Types example). - Action —
toast("Moved to trash", { action: { label: "Undo", onClick } })(the With action example). - Promise —
toast.promise(p, { loading, success, error })swaps a loading toast for success or error when the promise settles (the Promise example). - Custom —
toast.custom((id) => <YourJSX />)for a fully custom toast (the Custom JSX example).
Configuring the Toaster
Options that affect the whole stack go on <Toaster />, not individual toasts:
<Toaster position="top-center" richColors closeButton duration={4000} />
position moves the stack, richColors gives each type a colored surface, closeButton adds an X, and duration controls how long toasts persist. The Rich colors & close example shows richColors + closeButton.
Migrating from the old Toast
If you used shadcn's old useToast() / <Toast> API, Sonner replaces it: drop the <ToastProvider> and <Toaster /> from @/components/ui/toast, mount the Sonner <Toaster />, and replace toast({ title, description }) calls with toast(title, { description }). It's less boilerplate and the same idea.
Accessibility & theming
Sonner manages focus, screen-reader announcements (toasts are announced politely), and keyboard dismissal. Because it's a notification surface, keep messages short and don't put the only copy of critical information in a toast. The toast reads your design tokens — the wrapper maps Sonner's --normal-bg / --normal-text / --normal-border to --popover / --popover-foreground / --border — so it follows your theme, including dark mode, with no overrides.