Components
- Accordion
- Alert
- Alert Dialog
- Aspect Ratio
- Attachment
- Avatar
- Badge
- Breadcrumb
- Bubble
- Button
- Button Group
- Calendar
- Card
- Carousel
- Chart
- Checkbox
- Collapsible
- Combobox
- Command
- Context Menu
- Date Picker
- Dialog
- Drawer
- Dropdown Menu
- Empty
- Field
- Hover Card
- Input
- Input OTP
- Input Group
- Item
- Kbd
- Label
- Marker
- Menubar
- Message
- Message Scroller
- Native Select
- Navigation Menu
- Pagination
- Popover
- Progress
- Radio Group
- Resizable
- Scroll Area
- Select
- Separator
- Sheet
- Sidebar
- Skeleton
- Slider
- Sonner
- Spinner
- Switch
- Table
- Tabs
- Textarea
- Toggle
- Toggle Group
- Tooltip
- New Component
Elements
Charts
Icons
import { toast } from "sonner";
import { Button } from "@/components/ui/button";
import { Toaster } from "@/components/ui/sonner";
export const SonnerDemo = () => (
<div className="flex flex-col gap-4">
<Toaster />
<div className="flex flex-wrap gap-2">
<Button variant="outline" onClick={() => toast("File saved successfully.")}>Default</Button>
<Button variant="outline" onClick={() => toast.success("Changes saved.")}>Success</Button>
<Button variant="outline" onClick={() => toast.error("Something went wrong.")}>Error</Button>
<Button variant="outline" onClick={() => toast.warning("Disk space is low.")}>Warning</Button>
<Button variant="outline" onClick={() => toast.info("A new version is available.")}>Info</Button>
<Button
variant="outline"
onClick={() =>
toast.loading("Uploading…", {
duration: 3000,
})
}
>Loading</Button>
<Button
variant="outline"
onClick={() =>
toast("File deleted.", {
action: { label: "Undo", onClick: () => toast.success("Restored.") },
description: "report.pdf was moved to trash.",
})
}
>With action</Button>
<Button
variant="outline"
onClick={() =>
toast("Profile updated.", {
description: "Your changes have been saved to the server.",
})
}
>With description</Button>
</div>
</div>
);Setup
Add <Toaster /> once in your root layout. It reads the active theme automatically via useTheme.
// app/layout.tsx
import { Toaster } from "@/components/ui/sonner";
export default function RootLayout({ children }) {
return (
<html>
<body>
{children}
<Toaster />
</body>
</html>
);
}Toast types
Trigger toasts from anywhere in your app by importing toast from sonner.
import { toast } from "sonner";
toast("File saved");
toast.success("Changes published");
toast.error("Something went wrong");
toast.warning("Connection unstable");
toast.info("New version available");
toast.loading("Uploading…");With action
Pass an action object to add a labelled button inside the toast.
toast("Message deleted", {
action: {
label: "Undo",
onClick: () => restoreMessage(),
},
});With description
Add a description string for secondary context below the title.
toast.error("Upload failed", {
description: "The file exceeds the 10 MB limit.",
});Dismiss
Call toast.dismiss with the returned ID to close a toast programmatically.
const id = toast.loading("Saving…");
await save();
toast.dismiss(id);
toast.success("Saved!");Props
Toaster
Toaster forwards all Sonner ToasterProps and adds theme awareness.
| Prop | Type | Default | Description |
|---|---|---|---|
position | Sonner ToastPosition | "bottom-right" | Screen position of the toast stack |
richColors | boolean | false | Use semantic colours for success/error/warning/info |
expand | boolean | false | Expand all toasts instead of stacking |
duration | number | 4000 | Auto-dismiss delay in milliseconds |
visibleToasts | number | 3 | Maximum number of visible toasts |
closeButton | boolean | false | Show a close button on each toast |
Usage
// 1. Mount once in root layout
import { Toaster } from "@/components/ui/sonner";
<Toaster />
// 2. Call toast() anywhere
import { toast } from "sonner";
toast.success("Profile updated");
toast.error("Save failed", {
description: "Please try again.",
action: { label: "Retry", onClick: retryFn },
});Specs
# Mint — Sonner Specs
## Component
- name: sonner
- file: registry/mint/sonner.tsx
- installs to: components/ui/sonner.tsx
- dependencies: sonner, next-themes, lucide-react
- registryDependencies: none
## What is it
A thin wrapper around the Sonner toast library that provides ephemeral
notification toasts. It synchronises the active next-themes theme with
Sonner, injects design-system icons per toast type, and maps CSS tokens
onto Sonner's custom property slots. Prefer it over custom alert components
for transient, non-blocking feedback; do not use it for persistent messages
that require user acknowledgement.
## Visual identity
Toasts use the popover surface (--popover / --popover-foreground) and the
shared border token, giving them the same floating-layer feel as dropdowns and
popovers. Corner radius inherits --radius (1.25rem), keeping the look
consistent with the rest of the Mint design system.
## Design tokens
--popover: oklch(1 0 0) / oklch(0.269 0 0) — toast background (light / dark)
--popover-foreground: oklch(0.145 0 0) / oklch(0.985 0 0) — toast text (light / dark)
--border: oklch(0.88 0.04 155 / 60%) / oklch(0.32 0.05 155 / 40%) — toast border (light / dark)
--radius: 1.25rem — corner radius
## External dependencies
- sonner: provides Toaster component and toast() imperative API
- next-themes: provides useTheme() for light/dark synchronisation
## States
- loading: Loader2Icon with animate-spin; dismiss programmatically with toast.dismiss(id)
- success: CircleCheckIcon (size-4)
- error: OctagonXIcon (size-4)
- warning: TriangleAlertIcon (size-4)
- info: InfoIcon (size-4)
## Conventions
- Mount Toaster once in the root layout — never per-page or per-component
- Import toast from "sonner" directly — do not re-export it from the wrapper
- Use toast.loading + toast.dismiss(id) for async operation feedback
- Avoid stacking more than 3 toasts; use visibleToasts prop to enforce this
- Pass richColors to activate semantic fill colours for success/error/warning/info types
- For actions, pass an action object with label and onClick; do not build custom toast children for simple confirmationsInstallation
$ npx shadcn add \https://gin-design.vercel.app/sonner