body { font-family: system-ui, -apple-system, “Segoe UI”, Roboto, “Helvetica Neue”, Arial; line-height:1.6; color:#111; margin:2rem; max-width:900px; }
pre { background:#0f1724; color:#e6f1ff; padding:1rem; overflow:auto; border-radius:6px; }
code { background:#f4f6f8; padding:.15rem .35rem; border-radius:4px; font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, “Roboto Mono”, “Courier New”, monospace; }
h1,h2 { color:#0b4a6f; }
a { color:#0b6fb5; }
blockquote { border-left:4px solid #e2e8f0; padding-left:1rem; color:#334155; background:#f8fafc; border-radius:6px; padding:1rem; }
.highlight { background:#fff7ed; padding:.15rem .35rem; border-radius:4px; }
.meta { color:#475569; font-size:.95rem; margin-bottom:1rem; }
.kbd { background:#111827; color:#fff; padding:.05rem .4rem; border-radius:4px; font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, “Roboto Mono”, monospace; font-size:.9rem; }
.backlinks { margin-top:1rem; font-size:.95rem; }
Sonner is a focused React toast notifications library that prioritizes a small API surface and developer ergonomics. It provides a Toaster container and imperative functions (like toast), covering the common needs for ephemeral UI alerts: success, error, loading, and custom renders. If you need lightweight notifications without complex scaffolding, Sonner is a solid choice.
Compared to heavier systems, Sonner keeps the core concepts simple: mount a <Toaster/> once (usually at the app root), then call toast from anywhere. This pattern minimizes prop drilling and fits well with modern React apps that use hooks and async/await patterns.
Sonner also fits nicely into a progressive enhancement approach — toasts remain client-side UI, but the API makes it easy to wire async operations (such as form submission or uploads) so the user receives immediate feedback during each step of the process.
Install Sonner via npm or Yarn. The package name is sonner, install with your preferred package manager and then mount the Toaster once in your React tree.
# npm
npm install sonner
# or yarn
yarn add sonner
Basic setup: import the Toaster component into your root (App or index) and include it once. This provides the “slot” for all toast messages; the library handles DOM placement and stacking.
Example root-level mount:
import React from 'react';
import { Toaster } from 'sonner';
export default function App() {
return (
<Toaster position="top-right" />
<YourRoutesOrUI />
>
);
}
</code>
Read a hands-on sonner tutorial with advanced patterns and examples.
With the Toaster mounted, you trigger notifications imperatively using toast. Notifications can be plain messages or typed variants like success and error. The patterns are intentionally simple so you can call them from event handlers or async flows.
Typical usage examples:
import { toast } from 'sonner';
function onSave() {
toast('Saved successfully'); // plain toast
toast.success('Saved!'); // success variant
toast.error('Could not save'); // error variant
}
// dismiss programmatically
const id = toast('Temporary message');
toast.dismiss(id);
IDs returned by toast allow updates or dismissals. Use this to replace a "loading" toast with a "success" toast once an operation completes — a pattern we'll formalize with promise handlers below.
Sonner supports promise-aware toasts so you can map a Promise lifecycle to three states: loading, success, and error. This yields a concise UX for network requests, file uploads, or any async workflow where you want continuous user feedback.
Commonly you use toast.promise (or equivalent) with an active Promise and a configuration object for messages. The library shows the loading message immediately, then replaces it based on the Promise result. This avoids janky "flash" toasts and keeps feedback consistent.
// pattern for promise toasts
const save = async (data) => {
const promise = api.save(data); // returns a Promise
toast.promise(promise, {
loading: 'Saving…',
success: 'Saved successfully',
error: 'Save failed'
});
await promise;
};
Use this pattern to centralize UX for operations across your app. It pairs well with optimistic UI updates: show an optimistic change, then call toast.promise so the user knows whether the change actually persisted.
Sonner exposes imperative utilities but also provides hooks for tighter integration with component lifecycles. For example, you can create custom hooks that wrap toast calls to standardize messaging (translations, consistent phrasing, or telemetry hooks).
Pattern: create a domain-specific notifier hook that translates domain events into toasts. This isolates notification content from components and makes it easy to change tone, timing, or telemetry later.
import { toast } from 'sonner';
import { useCallback } from 'react';
export function useNotifier() {
const notifySave = useCallback(() => {
toast.success('Saved');
}, []);
const notifyError = useCallback(msg => {
toast.error(msg || 'Something went wrong');
}, []);
return { notifySave, notifyError };
}
For programmatic control, you can keep the returned toast ID and call toast.update or toast.dismiss if available. Wrap these calls in your async logic to maintain predictable notification lifecycles.
Sonner offers options to customize position, duration, and colors. You can typically pass props to the Toaster for global defaults and then override per-toast when needed. For custom content, Sonner supports rendering JSX inside toasts so you can include actions like buttons or links.
When adding buttons (for example, "Undo"), ensure the control is keyboard-focusable and intervals for auto-dismiss are sensible. Consider keeping interactive toasts on-screen until user dismissal if they require actions; ephemeral auto-dismissed toasts are best for passive feedback only.
Example: a custom toast with an "Undo" button helps recover from destructive actions. Keep the HTML accessible (use semantic buttons), and avoid too much content inside small toasts — they should be concise and actionable.
Toasts are transient but must still be accessible. Sonner uses ARIA live regions to announce messages to screen readers; confirm that the library's default behavior meets your a11y requirements and adjust ARIA attributes if necessary. Provide meaningful text and avoid relying solely on color to communicate state.
Performance: toasts are lightweight, but avoid spawning many toasts in quick succession. Batch or debounce notifications originating from rapid events. For repeated or noisy events (like streaming logs), aggregate messages into a compact summary instead of flooding the user.
Test toasts with keyboard navigation and screen readers. Check whether the Toaster container traps focus inadvertently and ensure actions inside toasts are reachable via tab order and properly labeled for assistive technology.
Keep messages short and actionable: name the event and, when useful, the next user step (e.g., "Saved — changes will appear after refresh"). Avoid long paragraphs inside toasts; if you need a long explanation, consider a modal or inline expansion.
Use appropriate variants for severity. Reserve error toasts for actionable failures, use success for confirmations, and use neutral toasts for informational updates. Overusing success messages for trivial events trains users to ignore them.
Pro tip: centralize messages and translations. Store toast strings in a single file or a notification service. This improves consistency, makes A/B testing easier, and supports localization without scattered magic strings.
Here's a small component example showing a submit button that uses Sonner and promise-toasts. This pattern is production-ready: start the toast, await the promise, let Sonner update the UI automatically, and handle errors in a catch block.
import React from 'react';
import { toast } from 'sonner';
export default function SaveButton({ data }) {
async function handleSave() {
const p = api.save(data);
toast.promise(p, {
loading: 'Saving…',
success: 'Saved successfully',
error: 'Save failed'
});
try {
await p;
} catch (err) {
console.error(err);
}
}
return <button onClick={handleSave}>Save</button>;
}
Alternatively, use a notifier hook to keep components thin and declarative. This also helps with testing: you can mock the notifier and assert that correct messages were requested rather than verifying DOM changes directly.
Remember to mount <Toaster /> at the app root or layout. Without it, toast calls are no-ops or fail silently.
Below is an expanded semantic core useful for SEO optimization and content mapping. Use these keyword groups to drive headings, code examples, and FAQ content without keyword stuffing.
Primary:
- sonner
- sonner tutorial
- sonner installation
- sonner setup
- sonner example
- sonner customization
- sonner promise
Secondary / intent-based:
- React toast notifications
- React toast library
- React toast messages
- React notification library
- React alert notifications
- React notification system
- React toast hooks
- React toast library comparison
- toast.promise React
LSI / related phrases:
- toast notifications React
- toast messages UI
- toast styling and themes
- accessible toast notifications
- toast lifecycle (show, update, dismiss)
- promise-based notifications
- custom toast render
- Toaster component
- toast variants (success, error, loading)
- programmatic toast control
- notification UX patterns
Use these clusters as primary/secondary/LSI terms throughout your page copy, code comments, and metadata to cover intent variations (informational, commercial, how-to).
For a detailed walkthrough and additional advanced techniques, see this community guide on advanced toast notifications: advanced toast notifications with sonner in React. That article includes practical examples and deeper customization patterns.
You can also reference the official package page for installation details and changelog (search npm for sonner).
Concise answers to the most common Sonner questions.
A: Install with npm install sonner (or yarn), then mount <Toaster /> once at the app root. Import toast where you need to trigger notifications. Example: import { Toaster } from 'sonner'; in App and import { toast } from 'sonner'; in components.
A: Use toast.promise(promise, { loading, success, error }). It shows a loading toast immediately, then replaces it with the success or error message depending on resolved state. This keeps async UX concise and consistent.
A: Pass props to <Toaster /> for global defaults (position, duration, color options) and render JSX inside individual toasts when you need actions. Ensure buttons are keyboard-focusable and ARIA-labeled. For global theme changes, wrap Toaster or supply a custom theme object if supported.
{
"@context": "https://schema.org",
"@type": "TechArticle",
"mainEntityOfPage": {
"@type": "WebPage",
"@id": "https://dev.to/0g7uvdlgtm/advanced-toast-notifications-with-sonner-in-react-2m62"
},
"headline": "Sonner for React: Toast Notifications Tutorial & Examples",
"description": "Practical Sonner tutorial for React: install, setup, toast.promise, hooks, and customization. Examples and best practices to ship robust notifications.",
"author": {
"@type": "Person",
"name": "Author"
},
"publisher": {
"@type": "Organization",
"name": "YourSite",
"logo": {
"@type": "ImageObject",
"url": "https://example.com/logo.png"
}
},
"datePublished": "2026-03-09",
"keywords": "sonner, React toast notifications, sonner tutorial, toast.promise, react toast hooks"
}
{
"@context": "https://schema.org",
"@type": "FAQPage",
"mainEntity": [
{
"@type": "Question",
"name": "How do I install and set up Sonner in a React project?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Install with npm install sonner or yarn add sonner, mount at the app root, and import toast where needed."
}
},
{
"@type": "Question",
"name": "How can I use Sonner with Promises to show loading/success/error messages?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Use toast.promise(promise, { loading, success, error }) to map a promise lifecycle to toast states."
}
},
{
"@type": "Question",
"name": "What are the best ways to customize Sonner toasts (styling and actions)?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Configure global defaults on and render custom JSX per toast for actions; ensure accessibility and keyboard focus."
}
}
]
}