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

1 Configure registry — once per project
{
  "registries": {
    "@designrevision": "https://registry.designrevision.com/r/{name}.json"
  }
}

Add to your existing components.json. Requires shadcn/ui v2.3+.

2 Install the component

Packages

sonner
next-themes
utils

Props

No props documented yet.

Copied!
components/ui/sonner.tsx
"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

sonner
button

Props

No props documented yet.

Copied!
components/ui/sonner-demo-01.tsx
"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

sonner
button

Props

No props documented yet.

Copied!
components/ui/sonner-types-01.tsx
"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

sonner
button

Props

No props documented yet.

Copied!
components/ui/sonner-description-01.tsx
"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

sonner
button

Props

No props documented yet.

Copied!
components/ui/sonner-action-01.tsx
"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

sonner
button

Props

No props documented yet.

Copied!
components/ui/sonner-promise-01.tsx
"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 `` — colored type surfaces with a close button.

Packages

sonner
button

Props

No props documented yet.

Copied!
components/ui/sonner-rich-01.tsx
"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

lucide-react
sonner
button

Props

No props documented yet.

Copied!
components/ui/sonner-custom-01.tsx
"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>
  )
}

Frequently asked questions

Yes — it is the current shadcn toast. shadcn deprecated its old Toast component in favour of Sonner, so the shadcn Sonner component is now the recommended toast. We add the full toast() API: types, descriptions, actions, promises, rich colors, and custom toasts.
Sonner is an opinionated toast library for React by Emil Kowalski (the author of vaul). The shadcn layer is a thin wrapper that themes it to your design tokens. Install it with npm install sonner; the shadcn component also uses next-themes to follow your light/dark theme.
Mount a single once near the root of your app — in the root layout (app/layout.tsx) or a top-level provider — not per component. Then call toast() from anywhere. The examples here each render their own Toaster so they work in isolation, but in your app you only need one.
Import toast from "sonner" and call it: toast("Saved"), or with a description toast("Saved", { description: "…" }). For typed toasts use toast.success / toast.error / toast.info / toast.warning. The Sonner and Types examples cover both.
Use toast.promise(yourPromise, { loading: "Uploading…", success: (data) => `${data.name} uploaded`, error: "Upload failed" }). Sonner shows the loading toast, then swaps to success or error when the promise settles. The Promise example demonstrates it.
Pass an action: toast("File moved to trash", { action: { label: "Undo", onClick: () => restore() } }). Add a cancel for a secondary dismiss. The With action example is the undo pattern.
Configure the Toaster, not each toast: . position moves the stack, richColors gives each type a colored surface, closeButton adds an X, and duration sets how long toasts stay. The Rich colors & close example shows richColors + closeButton.