import { toast } from "sonner"
import { Button } from "@/components/ui/button"
import { Toaster } from "@/components/ui/sonner"
export default function SonnerDemo() {
return (
<div>
<Toaster />
<Button
variant="outline"
onClick={() =>
toast("Event has been created", {
description: "Sunday, December 03, 2026 at 9:00 AM",
})
}
>
Show Toast
</Button>
</div>
)
}Installation
npx logic2b@latest add sonnerWorking with an AI assistant? Copy this prompt into Claude Code, Cursor or Copilot — it carries the install steps, a no-CLI fallback and a verification checklist.
Add the "sonner" item from the logic2b ui registry (https://ui.logic2b.com) to this project. Follow every step and verify at the end. ## Steps 1. If the project has no `components.json` yet, set up logic2b ui first: ```bash npx logic2b@latest init ``` 2. Install the item (the CLI resolves registry dependencies automatically): ```bash npx logic2b@latest add sonner ``` 3. Install any npm dependencies the command prints. ## If the CLI is not available Do it manually from the registry payload: 1. Fetch https://ui.logic2b.com/r/sonner.json. 2. Write every entry in `files[]` to its mapped project path (see below). 3. Repeat (recursively) for each name in `registryDependencies`. 4. Install every package listed in `dependencies` across those payloads. ## Registry reference - Index of every item: https://ui.logic2b.com/r/index.json - Item payload (full source): https://ui.logic2b.com/r/<name>.json - Usage examples per item: https://ui.logic2b.com/r/demos/index.json → https://ui.logic2b.com/r/demos/<demo>.json - Docs index for agents: https://ui.logic2b.com/llms.txt (full docs: https://ui.logic2b.com/llms-full.txt) - Every docs page is Markdown when you append `.md` to its URL. Registry file paths map to project paths like this: - `ui/*` → `@/components/ui/*` - `blocks/<name>/*` → `@/components/*` - `charts/*` → `@/components/charts/*` - `hooks/*` → `@/hooks/*` - `lib/utils.ts` → `@/lib/utils.ts` - `theme.css` → next to the project's Tailwind entry stylesheet ## Conventions (do not break these) - Tailwind CSS v4 (CSS-first config; no tailwind.config.js needed) and React 19. - All colors go through semantic tokens (`bg-primary`, `text-muted-foreground`, `border-border`, …). Never hardcode hex/oklch values in components. - Dark mode is class-based: toggle `.dark` on `<html>`. - Icons come from lucide-react. ## Verify before finishing 1. The dev server starts and the app renders without console errors. 2. TypeScript compiles (`tsc --noEmit` or the framework's check). 3. Components use the theme: a `<Button>` shows the primary token color, and toggling `.dark` on `<html>` switches the palette.
Install the dependencies:
npm install sonnerCopy into ui/sonner.tsx:
"use client"
import * as React from "react"
import { Toaster as Sonner, type ToasterProps } from "sonner"
function Toaster({ theme = "system", ...props }: ToasterProps) {
return (
<Sonner
theme={theme}
className="toaster group"
style={
{
"--normal-bg": "var(--popover)",
"--normal-text": "var(--popover-foreground)",
"--normal-border": "var(--border)",
} as React.CSSProperties
}
{...props}
/>
)
}
export { Toaster }Usage
Add the Toaster component once, then call toast() from anywhere.
import { Toaster } from "@/components/ui/sonner"
<Toaster />
import { toast } from "sonner"
toast("Event has been created")
API
The Toaster component wraps sonner’s Toaster and forwards every
ToasterProps. Toasts themselves are
created imperatively with toast().
| Prop | Type | Default |
|---|---|---|
theme |
light | dark | system |
system |
position |
top-left | top-center | top-right | bottom-left | bottom-center | bottom-right |
bottom-right |
richColors |
boolean |
false |
closeButton |
boolean |
false |
expand |
boolean |
false |
duration |
number (ms) |
4000 |
Examples
With an action
import { toast } from "sonner"
import { Button } from "@/components/ui/button"
import { Toaster } from "@/components/ui/sonner"
export default function SonnerActionDemo() {
return (
<div>
<Toaster />
<Button
variant="outline"
onClick={() =>
toast("Event has been created", {
description: "Sunday, December 03, 2026 at 9:00 AM",
action: {
label: "Undo",
onClick: () => toast("Event removed"),
},
})
}
>
Show toast with action
</Button>
</div>
)
}Promise
import { toast } from "sonner"
import { Button } from "@/components/ui/button"
import { Toaster } from "@/components/ui/sonner"
export default function SonnerPromiseDemo() {
const save = () =>
new Promise<void>((resolve) => setTimeout(resolve, 1500))
return (
<div>
<Toaster />
<Button
variant="outline"
onClick={() =>
toast.promise(save, {
loading: "Saving changes...",
success: "Changes saved",
error: "Could not save changes",
})
}
>
Save changes
</Button>
</div>
)
}