Sonner: Opinionated Toast Component for React
Sonner is an opinionated toast component for React, designed to be beautiful by default and simple to use. It emphasizes accessibility and provides a modern look and feel, inspired by macOS notifications. The library is currently stable at version 2.0.7 and receives regular updates, often with multiple patch releases between minor or major versions. Its key differentiators include built-in support for various toast types (success, error, info, warning, loading), rich customization options through props, and a strong focus on developer experience with a simple `toast()` API. Unlike some alternatives, Sonner aims to provide a consistent, aesthetically pleasing experience without requiring extensive styling, while still offering flexibility for specific needs. It also excels at handling asynchronous operations with its promise-based toast updates.
Common errors
-
Module not found: Can't resolve 'sonner/dist/style.css'
cause The CSS file for Sonner is not being correctly imported or found by the bundler.fixEnsure you have `import 'sonner/dist/style.css';` in your root `App.js`/`App.tsx` or `index.js`/`index.tsx` file. Verify your bundler configuration supports CSS imports. -
TypeError: toast is not a function
cause The `toast` utility function was not correctly imported or is being called on an undefined variable.fixEnsure you are using `import { toast } from 'sonner';` and that the import statement is at the top of your file. Check for typos in the function call. -
Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.
cause The `<Toaster />` component was not correctly imported or recognized.fixConfirm you are importing it as a named export: `import { Toaster } from 'sonner';`. Ensure you have `<Toaster />` present in your component tree. -
Error: Hydration failed because the initial UI does not match what was rendered on the server. There was an error while hydrating this message from the server: TypeError: Cannot read properties of null (reading 'removeChild')
cause This can occur in SSR/SSG environments if Sonner tries to access DOM elements before they are available, or if the markup differs between server and client.fixWrap the component rendering toasts in a `useEffect` hook with an empty dependency array to ensure it only runs on the client, or use a dynamic import with `ssr: false` if using Next.js or similar frameworks.
Warnings
- breaking Version 2.0.0 introduced breaking changes, primarily through the removal of deprecated props that were present in earlier major versions or beta releases. Users migrating from v1 or early v2 betas must review the official documentation for updated API usage.
- gotcha Prior to v2.0.5, users commonly encountered issues with the CSS import path, leading to unstyled toasts. This was a significant pain point for many users.
- gotcha Before v2.0.7, Sonner did not officially support multiple `<Toaster />` components within a single application, which could lead to unpredictable rendering or behavior issues if attempted.
- gotcha The `onDismiss` callback on toasts might not have fired consistently or reliably in versions prior to v2.0.4, impacting logic dependent on toast dismissal.
- gotcha In versions prior to v2.0.2, calling `toast.dismiss()` without providing a specific toast `id` would not dismiss any toasts, even if there was only one active.
Install
-
npm install sonner -
yarn add sonner -
pnpm add sonner
Imports
- Toaster
const { Toaster } = require('sonner');import { Toaster } from 'sonner'; - toast
const toast = require('sonner').toast;import { toast } from 'sonner'; - ToastOptions
import { ToastOptions } from 'sonner';import type { ToastOptions } from 'sonner';
Quickstart
import { Toaster, toast } from 'sonner';
import './index.css'; // Or wherever your Sonner CSS is located
function App() {
return (
<div>
<Toaster richColors position="bottom-right" />
<h1>Welcome to my App</h1>
<button onClick={() => toast('My first toast!')}>
Show Simple Toast
</button>
<button onClick={() => toast.success('Operation successful!')}>
Show Success Toast
</button>
<button onClick={() => toast.loading('Loading data...', {
id: 'loading-toast'
})}>
Show Loading Toast
</button>
<button onClick={() => {
toast.dismiss('loading-toast');
toast.error('Operation failed!');
}}>
Dismiss Loading & Show Error
</button>
</div>
);
}
export default App;