Sonner in React: Toast Notifications, Hooks & Promise API
Quick guide: setup, examples, customization, and production-ready patterns for sonner — a modern React notification library that makes toast messages fast, accessible, and extensible.
Why choose Sonner for React toast notifications?
Sonner is a compact React notification library built around predictable hooks and a minimal API surface. If you’ve used other React toast libraries, sonner feels intentionally focused: it covers the common needs of transient alerts—success, error, info, loading—without shipping heavy CSS or complicated lifecycle plumbing. That makes it ideal when you want a lean React notification system that respects performance budgets.
From a developer perspective, sonner emphasizes hooks-first usage and a declarative API that integrates with React state and promises. That means you can call a toast from any component, from asynchronous logic, or directly inside custom hooks. For applications that need programmatic alerts (for example, form validation, network responses, or optimistic updates), this approach keeps UX predictable and code readable.
For product managers and UX designers, sonner’s out-of-the-box accessibility and theming options let you ship consistent alert patterns quickly. The library plays nicely with dark mode and design tokens, and its default animations are subtle (no clown horns). If you want a deeper walkthrough, see this sonner tutorial for advanced patterns and examples: sonner tutorial.
Installation & setup
Get started with sonner by installing the package and adding a provider to your app root. Most React apps use npm or yarn; the install step is intentionally small to remain dependency-light. Sonner’s docs show both the package install and a basic provider pattern — see the official repo for the canonical sonner installation instructions.
After installing, place the <Toaster /> (or equivalent) component near the top of your component tree—commonly inside App.jsx or a layout component. That single provider renders toast portals and centralizes configuration for position, duration, and animations. Because the provider mounts once, runtime cost is negligible and you avoid props drilling or passing event handlers through components.
A concise setup checklist (two steps) keeps this deterministic:
- Install sonner and import
Toasterinto your app root. - Use the hook or programmatic API (
toast) from any component to trigger messages.
Example (very small):
import { Toaster, toast } from 'sonner'
function App(){ return (
<>
<Toaster />
<MyForm />
</>
)}
// somewhere in a component
toast.success('Saved successfully')
Basic usage: hooks, API and a simple example
Sonner exposes a minimal API: a Toaster component and an imperative toast object with helper methods like toast.success, toast.error, and toast for custom content. There’s also a hook-focused pattern you can adopt for finer control. The API surface is small, which reduces cognitive overhead when you’re wiring notifications into forms, service layers, or global stores.
Using the hook pattern (React toast hooks), you can wrap notification logic inside custom hooks for reuse. For example, create a useApiFeedback hook that shows loading, success, and error toasts around fetch calls. This centralizes behavior and ensures consistent messaging across the app. Hooks integrate naturally with React’s lifecycle and make cleanup trivial.
Here’s a minimal component example that demonstrates the common flow: trigger a loading toast, call an async API, then replace the loading toast with success or error. This approach leverages sonner’s promise-style integration as well (covered below), but you can also perform manual control with ids returned from the API.
function SubmitButton(){
const handle = async ()=>{
const id = toast.loading('Uploading...')
try{
await api.upload()
toast.success('Uploaded', { id }) // replace
}catch(e){
toast.error('Upload failed', { id })
}
}
return <button onClick={handle}>Upload</button>
}
Working with the Promise API (sonner promise)
One of sonner’s convenient patterns is the promise helper, which ties a toast’s lifecycle to a promise. Instead of manually showing a loading toast and then swapping it on resolution or rejection, you pass the promise and three labels (loading, success, error). The library manages replace semantics for you, ensuring a crisp UX without extra state variables.
This pattern is particularly useful for network-heavy operations and background sync tasks. It eliminates boilerplate and reduces the chance of leaking toasts or leaving a loading indicator visible after navigation. Use the promise API from within action handlers, custom hooks, or middleware where you already handle the promise and want succinct notifications.
Example usage with sonner’s promise helper (conceptually):
toast.promise(apiCall(), {
loading: 'Saving...',
success: 'Saved!',
error: 'Could not save'
})
Because sonner keeps the toast replacement atomic, you avoid flashes and ensure accessibility announcements happen in the right sequence—important for screen reader users.
Customization, theming and advanced patterns
Sonner is small but flexible. You can customize the appearance and behavior of toasts by passing props to the provider or by injecting component-level renderers for advanced cases. Common customization points include duration, placement, animation styles, and iconography. For consistent brand voice, wire the toast theme into your design tokens and map severity levels to color variables.
Component-level customization allows you to present richer content—like action buttons, links, or progress bars—inside a toast. Keep in mind that a toast’s purpose is transient feedback, so avoid monolithic content or complex interactions that require routing changes within the toast. For CTA-driven experiences, append a concise action or link with clear affordance and aria-labels.
Advanced patterns you’ll find useful in medium-to-large apps include centralized notification services (wrapping sonner in a domain-specific API), middleware integration to convert server-sent events into toasts, and queueing strategies that throttle the number of visible toasts to avoid overwhelm. These patterns preserve UX clarity while still delivering timely alerts.
Accessibility & performance considerations
Notifications are sensory interruptions—be mindful of how they interact with assistive technology. Sonner takes accessibility seriously by default: it uses live regions to announce changes and follows the standard practice of not stealing focus. Test voices, screen readers, and keyboard navigation to confirm the experience is non-disruptive for users relying on assistive tech.
Performance-wise, sonner is optimized for minimal bundle impact and runs with light DOM updates. The provider is a single mount point that renders a portal, so triggering hundreds of toasts in quick succession won’t cause severe layout thrashing. Still, implement throttling or collapse similar messages if your app can generate many alerts rapidly to protect both performance and the user’s attention.
For internationalized apps, ensure messages are localized prior to passing them to the toast API. Avoid building messages dynamically with unescaped HTML; prefer string templates or components where you control markup. This reduces XSS risk and keeps text nodes simple for translation tools and screen readers.
Troubleshooting & tips
If your toasts don’t appear, check that the <Toaster /> is rendered at app root and not conditionally unmounted. Common issues arise when the provider is inside a route component that’s not present on the initial render, making toasts unreachable from other parts of the app. Keep the provider stable and globally available.
If toasts persist or don’t replace correctly, audit your usage of ids and the promise helper. Sonner returns ids for programmatic updates—use them consistently when you want to update or dismiss a specific toast instead of creating duplicates. For complex flows, centralize toast invocation in domain hooks to make behavior predictable.
When integrating with state management (Redux, Zustand, etc.), avoid storing transient toast content in global state unless you need precise cross-tab coordination. Prefer direct calls to the toast API from effects or middleware to keep lifecycle tied to the event that triggers the notification.
Examples and real-world patterns
In production apps I often implement three patterns: (1) form feedback toasts for save/cancel actions, (2) global network monitors that surface connectivity or sync issues, and (3) user-action confirmations with a short undo affordance. These patterns map directly to sonner’s API and keep behavior consistent across the product.
Example: an optimistic update pattern shows a temporary undo toast when deleting an item, giving users a chance to revert. Use the toast’s action render to add a small button for undo; keep the handler idempotent and fast. That keeps UX snappy without navigating away from the current view.
For progressive enhancement, you can swap sonner for a server-driven notification system if you need cross-device alerts. Sonner remains the client-side delivery mechanism and can consume events from WebSockets or push notifications, translating them into ephemeral toasts for the active session.
Semantic Core (keyword clusters)
Primary, secondary, and clarifying keyword groups derived from the topic — use these to guide on-page optimization and internal linking.
Primary: - sonner - React toast notifications - React notification library - sonner tutorial - sonner installation - sonner setup Secondary: - React toast messages - React alert notifications - sonner example - React toast hooks - sonner promise - React toast library - sonner customization - React notification system Clarifying / LSI: - toast notifications in React - toast hooks - toast promise API - toast provider - toast theming and customization - accessible toast notifications - toast lifecycle and ids - toast performance and UX
Related user questions (popular queries)
Common searches and PAA-style prompts users ask when evaluating sonner or implementing toast messages:
- How to install sonner in a React project?
- What is the promise API in sonner and how do I use it?
- How do I customize sonner toast styles and animations?
- Can I use sonner with server-sent events or WebSockets?
- How to replace a loading toast with success/error in sonner?
- Is sonner accessible for screen reader users?
- How to use sonner with React hooks and custom hooks?
From that list, the three most relevant questions are answered in the FAQ below.
FAQ
How do I install and set up sonner in a React app?
Install with npm or yarn, import Toaster to your app root, and call toast from components. Example: npm install sonner, place <Toaster /> in App.jsx, then use toast.success('Saved'). For step-by-step guidance, check the official sonner installation docs and this practical sonner tutorial.
How does the sonner promise API work and when should I use it?
The promise API ties a toast to the lifecycle of a promise: you provide labels for loading, success, and error. Sonner replaces the loading toast with a final state automatically. Use it for network calls and async operations where you’d otherwise show a loading indicator then swap it for success/error—this reduces boilerplate and avoids toast leaks.
How can I customize appearance and ensure accessibility?
Configure theming via provider props or inject custom components for toast content. Map severity to your design tokens and keep messages concise. Sonner uses live regions and non-focus-stealing announcements by default, but test with screen readers and localized content to ensure messages are clear and non-disruptive.
Backlinks & references: Official sonner repo and docs: sonner installation. Advanced tutorial and walkthrough (examples and promise patterns): sonner tutorial. For core React hooks reference see the React docs: React hooks.




