Editor’s note: This article was last updated on 15 September 2023 to include the NotiStack React toast library.
In app development, it’s common to show important messages to users based on their actions or conditions. Toast notifications are a great way to do this because they’re lightweight and don’t disrupt the user experience.
While you can create your own custom React toast notifications, using a pre-built library with a wide range of features and customization saves you time and effort.
In this article, we’ll learn about toast notifications, understand their significance, and compare some of the most popular React toast libraries. We will delve into their features and benefits, so you can choose the best option for your project.
Jump ahead:
Toast notifications are a type of UI element commonly used in app development, including React applications. They are used to display brief, unobtrusive messages or notifications to users. These messages typically appear on the screen for a short period of time and then disappear, similar to how a slice of toast pops up from a toaster and then disappears.
The significance of toast notifications in React and other app development contexts lies in their ability to effectively communicate important information to users without disrupting their overall experience. Here are some key points highlighting the importance of toast notifications:
Given that React is the most popular choice for app development, there is a wide range of options available for implementing toast notifications. In the rest of this article, we will list and compare a number of popular React toast libraries that offer a diverse set of features and customization options.
We will compare these React libraries based on their features, usage, variants, configuration and style options, and the developer experience they provide. Each library comes with a working demonstration to help you kickstart the implementation. At the ed, we will rank these libraries based on this criteria.
React Hot Toast is a lightweight and high-performance toast notification library. It has a straightforward API that makes it easy to use, and it is customizable so that you can style and configure the notifications to match your needs:
useToaster()
Setting up basic toast notifications with React Hot Toast is straightforward. The library provides a range of methods through its toast API, such as success()
, error()
, and more, to handle different toast variations.
The Toaster
component serves as the container for all toast messages and is responsible for rendering them through the API. Here’s how simple it is to display a simple toast message using the API. Just pass the message as an argument to the toast()
method and attach it to the event modifier of a triggering element:
import toast, { Toaster } from "react-hot-toast"; const App = () => { return ( <div> <button onClick={() => toast("This is a simple toast.")}>Show Toast</button> <Toaster /> </div> ); }; export default App;
React Hot Toast offers five different toast variants: success
, error
, loading
, custom
, and promise
. The success
, error
, and loading
methods are used to show toast variations with a success message, an error message, or a message with a loading spinner icon, respectively:
import toast, { Toaster } from "react-hot-toast"; const successToast = () => toast.success("Success toast."); const errorToast = () => toast.error("Error toast."); const loadingToast = () => toast.loading("Loading toast..."); const App = () => { return ( <> <button onClick={successToast}>Show Success Toast</button> <button onClick={errorToast}>Show Error Toast</button> <button onClick={loadingToast}>Show Loading Toast</button> <Toaster /> </> ); }; export default App;
The toast.promise()
method is useful when you want to update a toast after a promise has been resolved or rejected, such as after fetching data from an API has been completed. Below is a quick example to demonstrate this:
import {useState} from 'react'; import toast, { Toaster } from "react-hot-toast"; const fetchData = async() => { ... } const App = () => { const [title, setTitle] = useState(""); const [body, setBody] = useState(""); const promiseToast = async () => { toast.promise(fetchData(), { loading: "Fetching data", success: (data) => { setBody(data.body); return "Data fetched successfully."; }, error: (error) => { return error.message; // Return the error message } }); }; return ( <div> <p> Click the following buttons to initiate different types of toast messages generated using React Hot Toasts library. </p> <div className="btn-group"> <button onClick={successToast}>Success</button> <button onClick={errorToast}>Error</button> <button onClick={loadingToast}>Loading</button> <button onClick={promiseToast}>Promise</button> <button onClick={customToast}>Custom</button> </div> {body && ( <div className="post"> <h1>Text loaded with a fetch request</h1> <p>{body}</p> </div> )} <Toaster /> </> ); }; export default App;
The second argument of the toast
method is an options
object that allows you to customize the behavior of each toast. You can specify the toast’s duration, alter its style, provide custom icons from an icon library, define its accessibility properties, and modify the theme of its icon:
import { AiFillAndroid } from "react-icons/ai"; toast.error("error toast", { duration: 7000, //icon config iconTheme: { primary: "white", secondary: "black", }, //ARIA config role: "status", ariaLive: "polite", //toast styles style: { background: "red", color: "whitesmoke", icon: <AiFillAndroid />, }, });
There are different ways to dismiss toasts with the React Hot Toast library. You can dismiss a single toast individually by using the toast.dismiss()
method and passing the reference to the toast you want to close as an argument. If you don’t pass a specific toast reference to the dismiss
method, it will dismiss all toasts simultaneously:
const successToast = toast.success('This is a successt toast'); toast.dismiss(successToast); toast.dismiss() // this will dismiss all toasts at once
React Hot Toast offer simple yet extensive customization options that allow you to tailor your toasts based on your project’s requirements.
In addition to its high customizability, React Hot Toast also has well-structured documentation, which provides more information about API usage, other components like Toaster
and ToastBar
, custom hook creation, and the internal API state, which is definitely worth exploring.
The NotiStack library refers to the notifications it generates as “snackbars,” a term particularly fitting for mobile app contexts. However, the library offers a wide array of customization options, granting you the flexibility to decide whether to maintain the toast-like behavior for your notifications or elevate them further to full-fledged snackbars.
NotiStack excels in performance, efficiently handling numerous on-screen notifications, making it perfect for chat apps or social media apps. Its flexibility allows it to display a variety of notifications, with customization options for positioning, style, and animation:
To use NotiStack, you first need to import the useNotistack
Hook and the Notifier
component from the library. Then, you can use the useNotistack
Hook to get a reference to the NotiStack instance. This instance can be used to display notifications, close notifications, and manage the notification queue.
To display a notification, you can use the enqueueSnackbar
method of the Notistack instance. This method tasks an object as a parameter, which contains the properties of the notification. The following code shows how to display a simple text notification:
import { useNotistack } from 'notistack'; const App = () => { const notistack = useNotistack(); return ( <button onClick={() => notistack.enqueueSnackbar('This is a notification.')}> Display notification </button> ); };
You can also use the enqueueSnackbar
method to display more complex notifications, such as notifications with alerts or modals. For example, the following code shows how to display a notification with an alert:
import { useNotistack } from 'notistack'; const App = () => { const notistack = useNotistack(); return ( <button onClick={() => notistack.enqueueSnackbar('This is a notification with an alert.', { variant: 'error', action: (key) => { // Do something when the user clicks the action button. }, })}> Display notification </button> ); };
NotiStack supports a variety of notification variants, which can be used to change the appearance of the notification, including notifications for success, info, warning, error, and the default one. The example below covers the implementation of each of the variants:
import { SnackbarProvider, useSnackbar } from "notistack"; const App = () => { const { enqueueSnackbar } = useSnackbar(); const showSnackbar = (variant) => { enqueueSnackbar(`This is a ${variant} snackbar!`, { variant: variant, }); }; return ( <div> <button onClick={() => showSnackbar("success")}>Show Success Snackbar</button> <button onClick={() => showSnackbar("info")}>Show Info Snackbar</button> <button onClick={() => showSnackbar("warning")}>Show Warning Snackbar</button> <button onClick={() => showSnackbar("error")}>Show Error Snackbar</button> <button onClick={() => showSnackbar("default")}>Show Default Snackbar</button> </div> ); }; export default App;
NotiStack provides versatile configuration options for notifications, applied globally via SnackbarProvider
or individually with enqueueSnackbar()
. Global settings standardize behavior and appearance. For example, anchorOrigin
controls position, autoHideDuration
sets display time, and maxSnackbars
limits concurrent notifications:
import { SnackbarProvider, useSnackbar } from 'notistack'; const App = () => { const { enqueueSnackbar } = useSnackbar(); return ( <SnackbarProvider anchorOrigin={{ vertical: 'top', horizontal: 'right' }} autoHideDuration={3000} maxSnack={3} // Updated to maxSnack > <button onClick={() => enqueueSnackbar('This is a notification!')}> Show notification </button> </SnackbarProvider> ); }; export default App;
For specific notifications, customize with options like action
, anchorOrigin
, and autoHideDuration
. Use dense
to adjust the size for smaller screens and control animations through transition
:
import { SnackbarProvider, useSnackbar } from 'notistack'; const App = () => { const { enqueueSnackbar } = useSnackbar(); const showCustomSnackbar = () => { enqueueSnackbar('This is a custom notification!', { anchorOrigin: { vertical: 'bottom', horizontal: 'left' }, autoHideDuration: 5000, dense: true, }); }; return ( <div> <button onClick={showCustomSnackbar}>Show custom notification</button> </div> ); }; export default App;
The NotiStack library offers an uncomplicated and user-friendly API, facilitating an easy start. It features comprehensive documentation, complete with examples and tutorials, and is actively developed and maintained to address feedback and bug reports.
Here’s a quick demo for using the NotiStack library:
See the Pen
NotiStack Demo by Rahul (@_rahul)
on CodePen.
React-Toastify offers unique features such as enhanced customization, bidirectional (RTL) language support, and additional mobile interactions.
These features empower users to finely customize animations, positions, and durations; display notifications in different languages; and enable actions such as swiping to dismiss and tapping to open:
React-Toastify has a similar API to React Hot Toast that provides a toast
method to access the different toast variants. The ToastContainer
component is required to contain and render the toast notifications:
import { ToastContainer, toast } from "react-toastify"; import "react-toastify/dist/ReactToastify.css"; const App = () => { const successToast = () => toast.success("This is a success toast!"); return ( <div className="App"> <button onClick={successToast}>show success toast</button> <ToastContainer /> </div> ); } export default App;
React-Toastify offers six toast variants: success
, error
, warn
, info
, dark
, along with a default variant, all of which are self-explanatory. The following code shows their straightforward implementation in a React component:
import { toast } from "react-toastify"; import "react-toastify/dist/ReactToastify.css"; const App = () => { return ( <> <button onClick={() => toast.success("Success toast")}> Show Success Toast </button> <button onClick={() => toast.error("Error toast")}> Show Error Toast </button> <button onClick={() => toast.warning("Warning toast")}> Show Warning Toast </button> <button onClick={() => toast.info("Info toast")}>Show Info Toast</button> <button onClick={() => toast.dark("Dark mode toast")}> Show Dark Mode Toast </button> <button onClick={() => toast("Default toast")}>Show Default Toast</button> </> ); }; export default App;
The dark-mode-powered toast sets the Toastify library apart from others in terms of toast UI and styling, providing you with an easy way to integrate it with your app’s dark mode.
Similar to React Hot Toast, we can pass an options
object as the second argument to a React-Toastify toast
to define different behaviors for it:
toast.dark("This is a success toast!", { position: toast.POSITION.BOTTOM_RIGHT, autoClose: 2000, pauseOnHover: true, draggable: true, });
Additionally, we have the option to customize the default toast animation using the cssTransition
method, which accepts an object where we can specify the enter
and exit
animations for the toast:
import "animate.css/animate.min.css"; import { ToastContainer, toast, cssTransition } from "react-toastify"; const bounce = cssTransition({ enter: "animate__animated animate__bounceIn", exit: "animate__animated animate__bounceOut", }); const customAnimationToast = () => { toast.dark("Hey đź‘‹, see how easy!", { transition: bounce, }); }; const App = () => { return ( <div className="App"> <button onClick={customAnimationToast}>show bounce toast</button> <ToastContainer transition={bounce} /> </div> ); } export default App;
Unlike React Hot Toast, where we can store a reference to a toast in a variable, with React-Toastify, we need to use the useRef
Hook to track the toast we want to update programmatically:
import { useRef } from "react"; export default function App() { let toastId = useRef(null); const successToast = () => { toastId = toast("Fetching data...", { autoClose: false }); }; const updateToast = () => { toast.update(toastId, { type: toast.TYPE.INFO, autoClose: 5000 }); } return ( <div> <button onClick={successToast}>show success toast</button> <Button onClick={updateToast}>update toast</Button> <ToastContainer ref={toastId} /> </div> ); }
React-Toastify offers a greater variety of toast styles compared to the other libraries of its kind, packed with many fantastic features. Its API shares similarities with both React Hot Toast and React Toast Notifications libraries, making it relatively easy to work with:
stackblitz-starters-uefvdx – StackBlitz
A create-react-app project based on react and react-dom
The React Toast Notifications library shares some similarities with React Hot Toast and React-Toastify, but it stands out as the simplest option, requiring minimal setup:
To use React Toast Notifications, simply wrap your app in the ToastProvider
component, which provides context for its descendant Toast
components:
// main.js import React from "react"; import ReactDOM from "react-dom"; import App from "./App"; import { ToastProvider } from "react-toast-notifications"; ReactDOM.render( <React.StrictMode> <ToastProvider> <App /> </ToastProvider> </React.StrictMode>, document.getElementById("root") );
With the useToast
Hook, you can use the addToast
method. It takes two arguments: a string containing the toast message and a configuration object. Within the config object, you can specify the toast appearance as success
and set autoDismiss
to true
:
import { useToasts } from "react-toast-notifications"; export default function App() { const { addToast } = useToasts(); const successToast = () => { addToast("This is a success toast", { appearance: "success", autoDismiss: true, }); }; return ( <div className="App"> <button onClick={successToast}>show success toast</button> </div> ); }
The useToast
Hook provides you with the following methods:
const { addToast, removeToast, removeAllToasts, updateToast } = useToast();
You already know how the addToast
method works. You can use the removeToast
method to remove a specific toast, and the removeAllToasts
method to remove all open toasts.
The updateToast
method is useful when we want to update a toast after an operation has been completed, such as after some data has been fetched.
In React Toast Notifications, you can create different types of toast notifications to convey various messages, such as success
, error
, warning
, and info
. These notifications are styled differently to visually represent their respective meanings.
Here’s an improved code example that demonstrates how to use these toast types:
import { useToasts } from 'react-toast-notifications'; const App = () => { const { addToast } = useToasts(); const showToast = (message, appearance) => { addToast(message, { appearance }); }; return ( <div> <button onClick={() => showToast("Success toast", "success")}> Show Success Toast </button> <button onClick={() => showToast("Error toast", "error")}> Show Error Toast </button> <button onClick={() => showToast("Warning toast", "warning")}> Show Warning Toast </button> <button onClick={() => showToast("Info toast", "info")}> Show Info Toast </button> </div> ); } export default App;
In React Toast Notifications, you can configure how toasts behave and appear by passing specific props to the ToastProvider
. These configurations will be inherited by the descendant toast components within the provider:
<ToastProvider placement="top-center" transitionDuration={2000} autoDismiss="true" autoDismissTimeout={5000}> <App /> </ChakraProvider>
When configuring ToastProvider
, the specified props such as placement
, transitionDuration
, autoDismiss
, and autoDismissTimeout
are passed as configuration options. These options are then inherited by the descendant toast components, ensuring that all toasts created within the escape of the provider adhere to the specified configuration.
This centralized configuration simplifies the management of toast behavior and appearance across your React application.
Although the API is straightforward, React Toast Notifications may not be an easy library to work with. The documentation is lacking, particularly in explaining how to pass a user ID to a toast and how to remove and update toast messages.
It’s worth noting that its developers have recently announced that React Toast Notifications is no longer maintained and recommend using other libraries such as React Hot Toast:
See the Pen
React Toast Notifications: A Simple Demo by Rahul (@_rahul)
on CodePen.
This lightweight library is easy to customize and style, providing simple and elegant toast notifications by default. However, due to its high level of customization, it may lack some pre-built features found in other libraries.
React Hot Toast is a suitable choice for projects that require minimalistic and straightforward toast notifications.
This versatile library offers a wide range of customization options and built-in animations, supporting various notification types and positions. It comes with good documentation and enjoys strong community support. Keep in mind that it’s slightly heavier compared to some of its alternatives and may make debugging more challenging in complex apps.
React-Toastify is a good choice for projects that demand feature-rich toast notifications with extensive customization options.
Specifically designed for Material UI users, NotiStack seamlessly integrates with this framework. It provides both global and per-toast configuration options, supports snackbars, and offers customization for both mobile and web apps. It works seamlessly with React Native and Next.js too.
Note that it may unnecessarily increase the project’s weight (~20KB) if Material UI is not already being used, as it adds Material UI as an additional dependency.
NotiStack is an ideal solution for projects using Material UI, offering a well-integrated, customizable, and feature-rich toast/snackbar notification solution.
This minimalistic, framework-agnostic library is highly customizable and allows you to create notifications from scratch. It’s lightweight and doesn’t enforce any specific styling. However, setting it up and styling it requires more manual work. Additionally, the library is no longer maintained and doesn’t support TypeScript.
Due to its small size, React Toast Notifications may still be suitable for projects where you need complete control over notification appearance and behavior, provided you’re comfortable with more hands-on customization.
After evaluating these four React toast libraries and gaining insight into their usage within our apps, I find myself favoring React Hot Toast above the others. Apart from its well-designed toasts and intuitive API, its promise
feature simplifies a lot of the setup needed for asynchronous toast updates.
Feel free to share your favorites in the comments and also suggest other libraries you believe deserve a spot on the list.
Install LogRocket via npm or script tag. LogRocket.init()
must be called client-side, not
server-side
$ npm i --save logrocket // Code: import LogRocket from 'logrocket'; LogRocket.init('app/id');
// Add to your HTML: <script src="https://cdn.lr-ingest.com/LogRocket.min.js"></script> <script>window.LogRocket && window.LogRocket.init('app/id');</script>
Hey there, want to help make our blog better?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowLearn to build scalable micro-frontend applications using React, discussing their advantages over monolithic frontend applications.
Build a fully functional, real-time chat application using Laravel Reverb’s backend and Vue’s reactive frontend.
console.time is not a function
errorExplore the two variants of the `console.time is not a function` error, their possible causes, and how to debug.
jQuery 4 proves that jQuery’s time is over for web developers. Here are some ways to avoid jQuery and decrease your web bundle size.
3 Replies to "Comparing the top React toast libraries"
Well written, good comparison. Exactly what I was looking for. Thanks!
I’m glad it was helpful Marc!
It’s a perfect comparison.
Thank you for your time and effort.