Toast notifications give users feedback without interrupting their workflow. The sonner library provides a clean, accessible toast system.
Step 1: Install Sonner
pnpm add sonner
Step 2: Add the Toaster Provider
// app/layout.tsx
import { Toaster } from "sonner";
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<body>
{children}
<Toaster
position="bottom-right"
richColors
toastOptions={{
className: "font-sans",
}}
/>
</body>
</html>
);
}
Step 3: Basic Toast Usage
"use client";
import { toast } from "sonner";
export function ActionButtons() {
return (
<div className="flex gap-3">
<button onClick={() => toast("Event has been created")}>
Default
</button>
<button onClick={() => toast.success("Successfully saved!")}>
Success
</button>
<button onClick={() => toast.error("Something went wrong")}>
Error
</button>
<button onClick={() => toast.warning("Are you sure?")}>
Warning
</button>
<button onClick={() => toast.info("New feature available")}>
Info
</button>
</div>
);
}
Step 4: Toast with Description
toast.success("Profile updated", {
description: "Your changes have been saved successfully.",
});
Step 5: Toast with Action Button
toast("File deleted", {
action: {
label: "Undo",
onClick: () => restoreFile(fileId),
},
});
Step 6: Promise Toast (Loading States)
async function handleSave(data: FormData) {
toast.promise(saveToDatabase(data), {
loading: "Saving changes...",
success: "Changes saved!",
error: "Could not save. Please try again.",
});
}
// With async/await
async function handleSubmit() {
const id = toast.loading("Submitting form...");
try {
await submitForm();
toast.success("Form submitted!", { id });
} catch {
toast.error("Submission failed", { id });
}
}
Step 7: Custom Toast Component
toast.custom((id) => (
<div className="flex items-center gap-3 rounded-xl border bg-white p-4 shadow-lg dark:border-gray-700 dark:bg-gray-800">
<img
src="/avatar.jpg"
alt="User"
className="h-10 w-10 rounded-full object-cover"
/>
<div className="flex-1">
<p className="text-sm font-medium">New message from Alex</p>
<p className="text-xs text-gray-500">Hey, the project looks great!</p>
</div>
<button
onClick={() => toast.dismiss(id)}
className="text-xs text-gray-400 hover:text-gray-600"
>
Dismiss
</button>
</div>
));
Step 8: Configuration Options
<Toaster
position="bottom-right" // top-left, top-center, top-right, bottom-left, bottom-center, bottom-right
richColors // Colorful success/error styles
expand={false} // Expand toasts by default
duration={4000} // Default duration in ms
closeButton // Show close button
theme="system" // light, dark, system
visibleToasts={3} // Max visible at once
/>
Step 9: Toast on Form Submission with Server Actions
"use client";
import { toast } from "sonner";
import { useTransition } from "react";
import { submitContactForm } from "@/app/actions";
export function ContactForm() {
const [isPending, startTransition] = useTransition();
function handleSubmit(formData: FormData) {
startTransition(async () => {
const result = await submitContactForm(formData);
if (result.success) {
toast.success("Message sent!", {
description: "We will get back to you within 24 hours.",
});
} else {
toast.error("Failed to send message", {
description: result.error,
});
}
});
}
return (
<form action={handleSubmit}>
{/* form fields */}
<button type="submit" disabled={isPending}>
{isPending ? "Sending..." : "Send Message"}
</button>
</form>
);
}
Step 10: Toast Utility Wrapper
// lib/toast.ts
import { toast } from "sonner";
export const notify = {
success: (message: string, description?: string) =>
toast.success(message, { description }),
error: (message: string, description?: string) =>
toast.error(message, { description }),
promise: <T>(
promise: Promise<T>,
messages: { loading: string; success: string; error: string }
) => toast.promise(promise, messages),
clipboard: (text: string) => {
navigator.clipboard.writeText(text);
toast.success("Copied to clipboard");
},
};
Need Polished UI Components?
We build web applications with professional UI patterns including toast notifications, modals, and interactive feedback systems. Contact us to start your project.