Sonner Alternative for React: 4 Toast Libraries Compared
You go looking for a Sonner alternative when something about the toast stops fitting: the bundle, a design system that fights its stylesheet, an accessibility review, or action buttons that are hard to hit on a phone. Sonner is still the default React toast for good reasons, so leaving it should fix a specific problem. This comparison puts Sonner next to react-hot-toast, React-Toastify and a source-owned toast on the API, the stack, swipe, screen readers, phones and bundle size, checked in October 2026 against each package's published code and docs.
We build Wingo UI, whose free Toast is the source-owned option here, so read this as a vendor's comparison with sources; it says where each of the others is the better pick. More head to head comparisons live under Comparisons and alternatives, and the guide to shadcn alternatives compares whole component libraries.
What is the best Sonner alternative for React?
The best Sonner alternative depends on what you are leaving for:
- A smaller bundle and your own markup: react-hot-toast. It measured 4.8 kB gzip in our build, half of Sonner, and its
useToasterhook lets you render every toast yourself. - More features built in: React-Toastify. Progress bars, a queue
limit,toast.update, a stacked mode, RTL and a notification history add-on, with no extra packages. - Behavior you can change: a toast whose source lives in your repository, such as the free Wingo UI Toast. It keeps a Sonner-style
toast()API, and the stack, the timers and the phone layout are code you can edit. - No problem to fix: stay on Sonner. It is the most downloaded React toast notification library of the four by a wide margin, and shadcn/ui installs it for Radix and React Aria projects.
How do Sonner, react-hot-toast and React-Toastify compare?
The table reads the latest version of each package on npm as of October 9, 2026. Sizes are our own measurement: each library's toaster component and toast function bundled with esbuild 0.28, minified, React left external, then gzipped. Sonner and React-Toastify inject their CSS from JavaScript, so their numbers include the styles. Downloads are npm's count for October 1 to 7, 2026.
The Wingo UI size needs a footnote: in most apps it is the heaviest of the four, because it animates with motion. In a shadcn-style project that already ships tailwind-merge, lucide-react and Radix, it adds 57.6 kB, motion included. If that app already uses motion too, it adds only its own 12.2 kB, and with nothing shared it is 69 kB, seven times Sonner. Its styles are Tailwind classes that compile into your app's stylesheet, so they are not in these numbers.
Sonner vs react hot toast: which one should you use?
Use Sonner if you want a stack, swipe and action buttons without writing them. Use react-hot-toast if you want the smallest package and plan to render toasts your own way. The two look alike at the call site until you need a button:
Beyond buttons, react-hot-toast lists toasts instead of stacking them, has no swipe and no keyboard handling, and pauses its timers only on mouse enter and leave, not for keyboard focus or a background tab. Success toasts default to 2 seconds, which is short for an Undo. Its strength is the headless entry: useToaster from react-hot-toast/headless hands you the toasts plus startPause, endPause and calculateOffset, the right shape if you want full control of the markup and will write the gestures yourself.
Sonner gives you polished defaults: a 356px stack, swipe in the directions its position allows, toast.promise, richColors and a close button, with timers that pause while you hover, while you swipe and while the tab is in the background. Its look comes from its own stylesheet, so matching a design system means CSS variables and classNames, or unstyled and your own markup.
When is React-Toastify the better pick?
Pick React-Toastify when you need features the others leave out: a progress bar on every toast, on by default, and a controlled progress value for uploads. limit holds extra toasts in a waiting queue, toast.update(id, options) changes a toast in place, stacked collapses the list, and the useNotificationCenter add-on keeps a history of toasts for an inbox. It handles RTL and positions its container with env(safe-area-inset-*) on phones.
Its defaults are the loudest of the four: a close button and a progress bar on every toast, 5 seconds on screen, and role="alert" on each toast, so screen readers interrupt the user for a "Saved" message unless you pass role="status". We found no prefers-reduced-motion rule in the 11.1.0 package, so the default Bounce transition plays for everyone; pass transition={Slide} or your own cssTransition if that matters to you.
If those defaults or the styling are why you want a React Toastify alternative, Sonner is the closest swap for the call sites (toast.success, toast.error, toast.promise). The main rename is the promise's loading message: React-Toastify calls it pending and Sonner calls it loading. A history with read state is an inbox, a different job: Wingo UI keeps it in a separate Notification Center with a bell and an unread count.
What does "shadcn toast" mean in 2026?
It depends on the project's base. Since July 2026 new shadcn/ui projects start on Base UI, and for those npx shadcn@latest add toast installs a Toast built on Base UI primitives (opens in a new tab), called with toast.add({ title, description }) and toast.promise. In Radix and React Aria projects, the old Toast is marked deprecated and the docs point to Sonner (opens in a new tab): npx shadcn@latest add sonner writes a components/ui/sonner.tsx that wraps the package, maps its colors to your --popover and --border tokens and reads the theme from next-themes.
So the shadcn toast in a Radix project is Sonner with your colors: you own a short wrapper, and the stack, timers and swipe stay in node_modules/sonner. The Base UI version hands you more of the markup, with behavior from Base UI's Toast parts. Per the Base UI docs (opens in a new tab), that means a 5 second default timeout, a limit of 3, swipe down or right, a priority: "high" option for urgent announcements, and F6 to move focus into the toast region.
What changes on a phone?
The phone is where these libraries differ most, on four points:
- Width. Sonner spans the screen below 600px with 16px gutters (
mobileOffset). React-Toastify spans it below 480px with square corners. react-hot-toast has no phone layout: its toasts cap at 350px and sit 16px from the edges. - Buttons. Sonner's default action and cancel buttons are 24px tall, exactly WCAG 2.2's minimum target size, and its close button is 20px, under it. All of them are far from the 44pt Apple recommends for iOS controls; our guide to minimum touch target size has the numbers.
- Safe areas. React-Toastify positions its container with the safe area insets. Sonner and react-hot-toast do not, so with
viewport-fit=covera bottom stack can sit on the iPhone home indicator until you add the inset to the offset yourself. Tailwind safe area insets shows the pattern. - Swipe. Sonner dismisses after 45px of travel or a quick flick. React-Toastify swipes on touch only by default and wants 80% of the toast's width. react-hot-toast has no swipe.
We built the Wingo UI Toast around that list. Below 768px toasts span the width with 16px gutters, each edge uses max(env(safe-area-inset-*), 16px), and mobilePosition="top" moves them clear of a bottom tab bar. Action and close buttons look 32px tall and keep a 44px hit area on touch screens. With no hover on a phone, a tap fans out the stack.
$ npx wingo-ui@latest add toastHow do the toasts sound to a screen reader?
All four announce through ARIA live regions; the difference is what gets interrupted. A polite announcement waits until the screen reader finishes speaking. An assertive one, which role="alert" implies, cuts in.
- Sonner wraps every toast in one
<section aria-live="polite">labeled "Notifications alt+T". A failed payment is announced as politely as "Copied". - react-hot-toast gives each toast
role="status"andaria-live="polite", and you can switch a single toast toalertthrough itsariaPropsoption. - React-Toastify gives each toast
role="alert", so every toast interrupts unless you change the role. - Wingo UI makes each toast its own polite
statusand switches errors, and any toast sent withimportant: true, torole="alert".
For the keyboard, Sonner's Alt+T focuses the list and Escape collapses it, React-Toastify's focuses a toast and pauses every timer until Escape, and react-hot-toast has none. In the Wingo UI Toast, Alt+T (Option+T on a Mac) focuses the newest toast, Tab walks through its buttons, Escape dismisses the focused toast, and timers pause while keyboard focus is inside, so there is time to reach Undo.
When should you skip the toast and use an inline alert?
Skip it when the message has to be read or acted on. A declined card, a form that failed to save, or a session about to expire need a message that stays next to the problem. Toasts time out, sit far from the field that caused them, and on a phone they can cover the submit button. Use an inline alert for those and keep toasts for confirmations, progress and quick undos. The free Alert follows the same split for screen readers: danger and warning tones use role="alert", the others role="status".
$ npx wingo-ui@latest add alertWhat does a source-owned toast give you?
A source-owned toast puts the whole component in your repository: the store, the stack, the gesture and the markup. You review it like the rest of your code, and nothing changes under you on npm update. The cost is that upstream fixes reach you only when you pull them. The Wingo UI Toast is free; install it with the CLI:
That writes components/ui/toast.tsx plus the button, the spinner and the hooks and helpers it uses. Mount the Toaster once, next to the app:
Then call toast from anywhere, even outside React or before the Toaster mounts:
Beyond those call sites, the file gives you:
- Updates by id. Calling
toast.loading("Uploading 3 photos… 2/3", { id: "upload" })again updates the toast in place. A new type with the same id, such astoast.success, starts it over, so the loading toast'sInfinityduration never sticks to the success. - Your tokens. The surface uses
bg-popoverand your theme's status tones, so dark mode needs nothemeprop. Visual props such asradius,widthandrichColorscan also be set app-wide throughUIProviderdefaults. - Updates that keep your edits.
npx wingo-ui@latest updatemerges a new release into the file you changed, as the updates docs describe.
The trade-offs, stated plainly. It is younger than the three packages, and Sonner has years of bug reports behind it. It costs more bytes than any of them, even in an app that already uses motion. In a shadcn project created with a Base UI style, install it with the Wingo UI CLI instead of shadcn add, because that style rewrites asChild, which the button relies on. The Notification Center is part of Wingo UI Pro; the Toast and the Alert are free.
How do you move from Sonner to the Wingo UI Toast?
Most call sites only change the import. The API follows Sonner's: toast, toast.success, error, warning, info and loading, toast.promise, toast.custom, toast.dismiss, the action, cancel and toasterId options, and the position, expand, visibleToasts, duration, richColors and closeButton props keep their names and defaults. The differences:
If you used the shadcn wrapper, delete components/ui/sonner.tsx, point the Toaster import at @/components/ui/toast, and replace from "sonner" in the files that call toast. Then drop any theme prop from the Toaster and the .unwrap() after promise toasts, which TypeScript flags.
Where should you start?
If Sonner works and nobody has complained, keep it. If the complaint is about phones, screen readers or a design system that will not bend, try a source-owned toast: run npx wingo-ui@latest add toast, which is free and needs no account, swap the import on a few call sites, and open the app on your own phone.
FAQ
What is the best Sonner alternative for React?
It depends on why you are leaving. react-hot-toast is the smallest and has a headless hook, React-Toastify has the most built-in features, and a source-owned toast like the free Wingo UI Toast keeps a Sonner-style API while every behavior lives in a file you can edit.
Is Sonner better than react-hot-toast?
Sonner does more out of the box: a collapsed stack, swipe to dismiss, action and cancel buttons, a promise toast and an Alt+T shortcut. react-hot-toast is about half the size at 4.8 kB gzip in our build and ships a headless useToaster hook, but it has no swipe, no keyboard shortcut and no built-in action buttons.
Does shadcn/ui still use Sonner for toasts?
It depends on the project's base. In Radix and React Aria projects the old Toast is deprecated and npx shadcn@latest add sonner installs a short wrapper around the sonner package. In Base UI projects, the default for new projects since July 2026, npx shadcn@latest add toast installs a Toast built on Base UI with a toast.add() API.
Which React toast library is the smallest?
react-hot-toast, at 4.8 kB minified and gzipped in our esbuild measurement in October 2026. Sonner came to 9.6 kB and React-Toastify to 9.8 kB, both including the CSS they inject from JavaScript.
Are toast notifications accessible to screen readers?
They are announced through ARIA live regions, but the libraries differ in urgency: Sonner announces everything politely, React-Toastify marks every toast role="alert" by default, and react-hot-toast and the Wingo UI Toast let single toasts interrupt. Anything the user must act on belongs in an inline alert, because toasts time out.
- Toast
- Sonner
- Comparisons
- React
- Accessibility
- Mobile UI