Getting Started
Components52
- Accordion
- Alert
- Alert Dialog
- Attachment
- Badge
- Breadcrumb
- Bubble
- Button
- Button Group
- Calendar
- Card
- Checkbox
- Collapsible
- Command
- Context Menu
- Data Table
- Dialog
- Drawer
- Dropdown Menu
- Empty
- Field
- Hover Card
- Input
- Input Group
- Item
- Kbd
- Label
- Marker
- Menubar
- Message
- Message Scroller
- Pagination
- Popover
- Progress
- Questionnaire
- Radio Group
- Scroll Area
- Select
- Separator
- Sheet
- Sidebar
- Skeleton
- Slider
- Sonner
- Spinner
- Switch
- Table
- Tabs
- Textarea
- Toggle
- Toggle Group
- Tooltip
"use client"
import { toast } from "sonner"
import { Button } from "@/components/ui/button"
export function SonnerDemo() {
return (
<Button
variant="secondary"
onClick={() =>
toast("Event has been created", {
description: "Sunday, December 03, 2023 at 9:00 AM",
action: {
label: "Undo",
onClick: () => console.log("Undo"),
},
})
}
>
Show toast
</Button>
)
}About#
Sonner is built and maintained by emilkowalski. This component restyles its toasts: the message sits on a raised card inside a muted shell, and the buttons sit on the shell beside it.
Installation#
Run the following command:
pnpm dlx shadcn@latest add https://ui.ikramhasan.com/r/sonner.json
Add the Toaster component
import { Toaster } from "@/components/ui/sonner"
export default function RootLayout({ children }) {
return (
<html lang="en">
<head />
<body>
<main>{children}</main>
<Toaster />
</body>
</html>
)
}Usage#
import { toast } from "sonner"toast("Event has been created.")Examples#
Types#
"use client"
import { toast } from "sonner"
import { Button } from "@/components/ui/button"
export function SonnerTypes() {
return (
<div className="flex flex-wrap justify-center gap-2">
<Button
variant="secondary"
onClick={() => toast("Event has been created")}
>
Default
</Button>
<Button
variant="secondary"
onClick={() => toast.success("Event has been created")}
>
Success
</Button>
<Button
variant="secondary"
onClick={() =>
toast.info("Be at the area 10 minutes before the event time")
}
>
Info
</Button>
<Button
variant="secondary"
onClick={() =>
toast.warning("Event start time cannot be earlier than 8am")
}
>
Warning
</Button>
<Button
variant="secondary"
onClick={() => toast.error("Event has not been created")}
>
Error
</Button>
<Button
variant="secondary"
onClick={() =>
toast.promise<{ name: string }>(
() =>
new Promise((resolve) =>
setTimeout(() => resolve({ name: "Event" }), 2000)
),
{
loading: "Loading...",
success: (data) => `${data.name} has been created`,
error: "Error",
}
)
}
>
Promise
</Button>
</div>
)
}Description#
"use client"
import { toast } from "sonner"
import { Button } from "@/components/ui/button"
export function SonnerDescription() {
return (
<Button
variant="secondary"
onClick={() =>
toast.success("Changes saved", {
description: "Your profile is now visible to your team.",
})
}
>
Show toast
</Button>
)
}Actions#
action and cancel render as Buttons on the shell. closeButton adds a close key at the end.
"use client"
import { toast } from "sonner"
import { Button } from "@/components/ui/button"
export function SonnerActions() {
return (
<div className="flex flex-wrap justify-center gap-2">
<Button
variant="secondary"
onClick={() =>
toast("Message archived", {
action: { label: "Undo", onClick: () => {} },
})
}
>
Action
</Button>
<Button
variant="secondary"
onClick={() =>
toast("Delete 3 files?", {
description: "This can't be undone.",
cancel: { label: "Cancel", onClick: () => {} },
action: { label: "Delete", onClick: () => {} },
})
}
>
Action and cancel
</Button>
<Button
variant="secondary"
onClick={() =>
toast("Your export is ready", {
description: "report-2026-10.csv",
closeButton: true,
})
}
>
Close button
</Button>
</div>
)
}Position#
Use the position prop to change where toasts appear.
"use client"
import { toast } from "sonner"
import { Button } from "@/components/ui/button"
const positions = [
"top-left",
"top-center",
"top-right",
"bottom-left",
"bottom-center",
"bottom-right",
] as const
export function SonnerPosition() {
return (
<div className="grid grid-cols-3 gap-2">
{positions.map((position) => (
<Button
key={position}
variant="secondary"
onClick={() =>
toast("Event has been created", {
position,
})
}
>
{position
.split("-")
.map((word, index) =>
index === 0 ? word[0].toUpperCase() + word.slice(1) : word
)
.join(" ")}
</Button>
))}
</div>
)
}API Reference#
See the Sonner API reference for every option of Toaster and toast(). Toaster accepts all of Sonner's props; any toastOptions.classNames you pass are merged with the built-in ones.