Sonner
An opinionated toast notification system for React. Built on sonner with UI.MD theming.
Installation
$
Usage
import { Toaster } from "@/components/ui/sonner"
import { toast } from "sonner"Examples
Default
Mount one <Toaster /> at the root of your app, then call toast() from anywhere to fire a notification.
Positioning
Set where toasts land with position on <Toaster /> (top/bottom paired with left/center/right). Pick a cell and the code below updates to match your selection.
Toast position
position="bottom-right"
API Reference
| Prop | Type | Default | Description |
|---|---|---|---|
| position | "top-left" | "top-center" | "top-right" | "bottom-left" | "bottom-center" | "bottom-right" | "bottom-right" | Where toasts are anchored on screen. |
| richColors | boolean | false | Enables sonner's built-in colored success/error styling. This kit applies its own semantic tints instead. |
| closeButton | boolean | false | Shows a close button on each toast. |
| duration | number | 4000 | How long a toast stays visible, in milliseconds. |
| width | number | string | 400 | Maximum width of the toast column, not a fixed width: toasts size to their own content and stop here. Set it on the Toaster rather than a single toast, since sonner sizes the list. Ignored below 600px, where toasts go full-bleed. |
"use client"
import * as React from "react"
import { useTheme } from "next-themes"
import { Toaster as Sonner, ToasterProps } from "sonner"
type MDToasterProps = ToasterProps & {
/** MAXIMUM width of the toast column, in px or any CSS length. Toasts size to
* their own content and stop here; they do not all sit at this width.
*
* Defaults to 400px. A toast should be as small as its message allows, so a
* one-line confirmation stays small and only a toast that has earned the room
* (a description, a row of buttons, a list of secondary actions) grows toward
* the cap. The `toast` item sets the floor, so short toasts never collapse to the
* width of the word inside them.
*
* It belongs here rather than on an individual toast: sonner sizes the toast
* list itself and positions each toast absolutely inside it, so this value is
* also the containing block every toast is measured against. Below 600px
* sonner ignores it and goes full-bleed on its own. */
width?: number | string
}
function Toaster({ width = 400, style, ...props }: MDToasterProps) {
const { theme = "system" } = useTheme()
return (
<Sonner
theme={theme as ToasterProps["theme"]}
className="toaster group"
style={
{
"--normal-bg": "var(--color-popover)",
"--normal-text": "var(--color-popover-foreground)",
"--normal-border": "var(--color-border)",
"--border-radius": "var(--radius-md)",
...(width !== undefined && {
"--width": typeof width === "number" ? `${width}px` : width,
}),
...style,
} as React.CSSProperties
}
{...props}
/>
)
}
export { Toaster }