NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
npm · #4620 most downloaded on npm
React notification made easy
Last release 5 months ago
19 Apr 2026
Release timing varies
gaps range from 8 days to 1.1 years
Most releases are documented
notes for 45 of the last 60 stable releases
Nothing withdrawn
no release was ever pulled
10 years old
170 releases · first in 2016
CSP nonce support. applies the nonce to the injected tag. Closes #1209.
<ToastContainer nonce={...}> applies the nonce to the
injected <style> tag. Closes #1209.onChange fires status: 'removed' synchronously on toast.dismiss() instead
of after the exit animation — observers (incl. useNotificationCenter) now
see correctly ordered events. Also guards against double-onClose. Closes #1275.'touchend', which never matched. Closes #1217.--y gets a unit). Thanks
@janpaepke, #1277.100vw again. Closes #1234.role="progressbar" now includes aria-valuenow, aria-valuemin, aria-valuemax.
Thanks @singhankit001, #1283. Closes #1259.pnpm link . no longer required for contributors).
Publish layout unchanged — addon still ships inside the main package.useStyleSheet (prerequisite for nonce).upload-artifact v3 → v4.Thanks to @janpaepke, @singhankit001, and reporters of the fixed issues.
This tag was signed with the committer’s verified signature .
fkhadra Fadi Khadra
SSH Key Fingerprint: upJRIiyrtnJkFGAUcA/AFuHr0PPU2wF+lqQusTosYmg Verified Learn about vigilant mode .
One column per quarter.
Nothing published for this version
Nothing published for this version
Nothing published for this version
- fix: remove margin on mobile - export ToastIcon type
Nothing published for this version
Nothing published for this version
Nothing published for this version
…nested elements, etc... It’s a significant breaking change, but it’s truly worth the effort. I can confidently say that the library can now seamlessly…
I’m super excited about this release! The main focus was on customization, and my goal was to empower you (and myself) so you can fully personalize the look and feel for the notifications.
In short, react-toastify should be able to blend into any design system.
The stylesheet is now injected automatically, so you no longer need to import it. The CSS file is still exported by the library.
import { ToastContainer, toast } from 'react-toastify';
function App(){
const notify = () => toast("Wow so easy !");
return (
<div>
<button onClick={notify}>Notify !</button>
<ToastContainer />
</div>
);
}
One of the top requests has been how to customize notifications. To be fair, until this release, it was quite challenging because it required users to override numerous CSS classes.
I’ve simplified the DOM structure of the notification by removing extraneous div elements, nested elements, etc... It’s a significant breaking change, but it’s truly worth the effort. I can confidently say that the library can now seamlessly integrate into any design system.
Below, I’ve implemented a couple of different designs using only Tailwind. I didn’t override a single CSS class from react-toastify 🤯!
[!NOTE]
Head to stackblitz to check the code.
How does it work in practice? On the left side, we have the old DOM structure vs the new one on the right side.
Toastify__toast-body and its child are now completely gone.CloseButton now uses an absolute position.Thanks to those changes, nothing will interfere with your content.
Toastify__toast has some sensible default values(e.g., border-radius, shadow, etc...) that can be customized using css or by updating the associated css variables:
width: var(--toastify-toast-width);
min-height: var(--toastify-toast-min-height);
padding: var(--toastify-toast-padding);
border-radius: var(--toastify-toast-bd-radius);
box-shadow: var(--toastify-toast-shadow);
max-height: var(--toastify-toast-max-height);
font-family: var(--toastify-font-family);
Allowing a custom progress bar wasn’t on my to-do list at all while working on this release. But seeing how easy it is to customize notifications now, I couldn’t resist 😆.
The best part is that you don’t have to compromise on features like autoClose, pauseOnHover, pauseOnFocusLoss, or even a controlled progress bar—it just works seamlessly for you.
<img width="686" alt="custom-progress-bar" src="https://github.com/user-attachments/assets/1ec197de-df35-4c13-9252-035368f78e47" />
Here is a small gist.
function App() {
const notify = () => {
toast(CustomComponent, {
autoClose: 8000,
// removes the built-in progress bar
customProgressBar: true
});
};
return (
<div>
<button onClick={notify}>notify</button>
<ToastContainer />
</div>
);
}
// isPaused is now available in your component
// it tells you when to pause the animation: pauseOnHover, pauseOnFocusLoss etc...
function CustomComponent({ isPaused, closeToast }: ToastContentProps) {
return (
<div>
<span>Hello</span>
<MyCustomProgressBar isPaused={isPaused} onAnimationEnd={() => closeToast()} />
</div>
);
}
[!NOTE]
Head to stackblitz for a live example.
ToastContainer and toast accept an ariaLabel prop(finally...). This is quite helpful for screen readers and also for testing.
For example, in cypress you could do cy.findByRole("alert", {name: "the aria label you specified"}).
toast("hello", {
ariaLabel: "something"
})
If a notification is visible and the user presses alt+t it will focus on the first notification allowing the user to use Tab to navigate through the different elements within the notification.
The hotKeys can be changed of course.
// focus when user presses ⌘ + F
const matchShortcut = (e: KeyboardEvent) => e.metaKey && e.key === 'f'
<ToastContainer hotKeys={matchShortcut} ariaLabel="Notifications ⌘ + F" />
Do you want to know whether the user closed the notification or if it closed automatically? Rest assured, this is now possible!
The signature of the onClose callback is now onClose(reason?: boolean | string) => void.
When the user closes the notification, the reason argument is equal to true. In the example below, I've named my argument
removedByUser to make the intent clear.
toast("hello", {
onClose(removedByUser){
if(removedByUser) {
// do something
return
}
// auto close do something else
}
})
If you are using a custom component for your notification, you might want more control over the reason, especially if it contains multiple call to actions.
import { ToastContentProps } from "react-toastify";
function CustomNotification({closeToast}: ToastContentProps) {
return <div>
You received a new message
<button onClick={() => closeToast("reply")}>Reply</button>
<button onClick={() => closeToast("ignore")}>Ignore</button>
</div>
}
toast(CustomNotification, {
onClose(reason){
switch (reason) {
case "reply":
// navigate to reply page for example or open a dialog
case "ignore":
// tell the other user that she/he was ghosted xD
default:
// 🤷♂️
}
}
})
Those hooks are unusable unless you deep dive in react-toastify source code to understand how to glue things together. This is not what I want for my users, it was a bad decision to expose them in the first place, I've learned a good lesson.
In hindsight, I should never have done this. The feature is practically not used. Below the new signature for each callback:
onOpen: () => voidonClose: (reason?: boolean | string) => voidreact-toastify/dist/ReactToastify.minimal.css has been removed.bodyClassName and bodyStyle are no longer needed.progressBarStyle in order to reduce the api surface. They are now better way to customize everything without relying on inline style.injectStyle has been removed. This function is no longer needed.Toastify__toast-body and its direct child have been removed.
I'm gradually rewriting part of the documentation. I've created a collection on stackblitz, this way you can find all the examples in one place. I'll keep adding more examples as I go.
I've been maintaining react-toastify for more than 8 years. If your company depends on it, consider contributing to its continued development and maintenance. Open-source software thrives with community support, and funding helps ensure we(the maintainers) can keep improving and innovating.
Every contribution, big or small, makes a difference and is greatly appreciated.
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Remove defaultProps on ToastContainer as it's deprecated #970
The code for this release has been sitting on my computer for almost a year but with so many things going on it was hard for me to release it but it's finally there! A good chunk of the code has been rewritten, a bunch of bugs have been fixed. I've also addressed the oldest open feature request (Jan 10, 2020) 😆.
<img width="347" alt="Screenshot 2023-12-17 at 14 53 50" src="https://github.com/fkhadra/react-toastify/assets/5574267/676689c7-64e4-4e74-aff8-b44b30088de5" />
By default, when the notification is hovered or the window loses focus, the timer for dismissing the notification is paused. There are many other situations where you might want to pause the timer as well. For instance, consider wanting to toggle the notification timer based on the document's visibility. This wasn't possible to do previously, but with the new API, it's a breeze.
document.addEventListener("visibilitychange", () => {
if (document.visibilityState === "visible") {
toast.play({ id: "123" });
} else {
toast.pause({ id: "123" });
}
});
More usages:
toast.play()
toast.pause()
toast.play({ containerId: "123" })
toast.pause({ containerId: "123" })
toast.play({ id: "123" })
toast.pause({ id: "123" })
toast.play({ id: "123", containerId: "12" })
toast.pause({ id: "123", containerId: "12" })
This feature was the oldest one in the backlog (Jan 10, 2020). I don't know if the user who requested this feature is still using the library but I bet thanks to her/him, a bunch of user will be happy.
toast.dismiss({ container: "123" })
toast.dismiss({ id: "123", containerId: "12" })
The method is backward compatible. toast.dismis() and toast.dismiss("123") work as usual.
You can limit the call to toast.isActive to a specific container.
toast.isActive(toastId, containerId)
When providing data to the notification, the content of data is correctly infered by typescript.
toast((props) => {
return <div>{props.data.foo}</div>
},{
data: {
foo: "bar"
}
})
When providing your own logic to display the icon, you now have access to the isLoading field.
const CustomIcon = props => {
if (props.isLoading) return <Spinner />;
switch (props.type) {
case 'info':
return <Info color={iconColor} />;
case 'success':
return <Success color={iconColor} />;
case 'error':
return <Error color={iconColor} />;
case 'warning':
return <Warning color={iconColor} />;
default:
return undefined;
}
};
<ToastContainer icon={CustomIcon} />
The initial release for this feature was planned right after the release of the v9. The code was their but things happen in life and I wasn't able to focus on the project that much.
That being said, I'm glad to finally release it.
To enable it, add the stacked prop to the ToastContainer. I also suggest to disable the progress bar :).
<ToastContainer stacked />
The progress bar leaves a background trail by default.
<img width="347" alt="Screenshot 2023-12-17 at 14 53 50" src="https://github.com/fkhadra/react-toastify/assets/5574267/676689c7-64e4-4e74-aff8-b44b30088de5" />
The opacity of the trail can be customized by overriding the css variable --toastify-color-progress-bgo.
// disable the trail
--toastify-color-progress-bgo: 0;
// increase the opacity
--toastify-color-progress-bgo: .8;
The minimun version of react required is now 18. This version has been released for more than a year. Nextjs, react-query already did this move as well, so I believe it's a good time for the library as well.
That being said, I know that not all code base have the chance to be running on the latest version of react, so I'm considering to have a package for v17 if the demand is high enough.
The enableMultiContainer props is not needed anymore and has been removed. As long as your container has an id assigned then you are good to go.
// before
<ToastContainer id="myContainer" enableMultiContainer />
// now 🎉
<ToastContainer id="myContainer" />
The toast.POSITION and toast.TYPE constants have been removed. Typescript came a long way since the initial release of the library. The ecosystem has matured to a point where such constants are not needed anymore.
The closeOnClick prop is now false by default instead of true. When using the library I keep on turning this feature off which make me realize that it was not a good default in the first place. To turn it on do as follow
<ToastContainer closeOnClick />
The draggable prop is set to touch by default instead of true. Which means that, by default, notifications are only draggable on touch devices (most likely mobiles and tablets). While swipping a notification on mobile feels natural, dragging on desktop is not. If you want your notification to be draggable regardless of the device type just set draggable to true.
<ToastContainer draggable />
Nothing published for this version
Add support for RSC (next app router): #951
Toast is undefined || Uncaught TypeError: Cannot read properties of undefined (reading 'content') #858 #952Mainly bug fixes as I'm working on the next major release.
Mainly bug fixes as I'm working on the next major release.
Nothing published for this version
Nothing published for this version
Added deprecation notice for the API below. They will be removed in the next major release
toast.promise let you type data for each state. This is useful when rendering something based on the response.For example:
interface Success {
username: string
}
interface Error {
err: string
}
toast.promise<Success,Error>(myPromise, {
success: {
render({ data }) {
return data.username;
}
},
error: {
render({ data }) {
return data.err;
}
}
})
toast.update accepts a generic as well to specify the data typeinterface TData {
username: string
}
toast.update<TData>(id, {
data: payload,
render({ data }) {
return `hello ${data.username}`
}
})
toast.done not dismissing toast #853Added deprecation notice for the API below. They will be removed in the next major release
| API | Why | Alternative |
|---|---|---|
onClick |
Not used that much, it's increasing the API surface for nothing | Can easily be implemented in userland. Just render a react component and attach the handler to it. toast(<div onClick={doSomething}>hello</div>) |
onOpen |
Does not play well with useEffect behavior in react18 (runs twice in dev mode) see #741 |
A better approach is to use toast.onChange see https://fkhadra.github.io/react-toastify/listen-for-changes/ |
onClose |
Does not play well with useEffect behavior in react18 (runs twice in dev mode) see #741 |
A better approach is to use toast.onChange see https://fkhadra.github.io/react-toastify/listen-for-changes/ |
toast.POSITION |
Reduce bundle size :) | Thanks to typescript, we now have autocomplete |
toast.TYPE |
Reduce bundle size :) | Thanks to typescript, we now have autocomplete |
fix draggable in strict mode #752
fix memory leak when multiple containers are used #772, thanks to @roblotter
Nothing published for this version
Nothing published for this version
fix missing generic in useNotificationCenter typing #796
useNotificationCenter typing #796Nothing published for this version
inject-style has now the correct file-name in bundle #779
This release does not work with CRA v4(2 years old) due to the lack of support for es modules. I strongly advise to upgrade to lastest CRA if possible
This release does not work with CRA v4(2 years old) due to the lack of support for es modules. I strongly advise to upgrade to lastest CRA if possible. Alternative solution:
Fix icon not updating after calling toast.update #770
toast.update #770Thanks to @Rambatino, @grit96, @Vl3oss, @eolme for this release
Thanks to @Rambatino, @grit96, @Vl3oss, @eolme for this release
Nothing published for this version
There are 2 breaking changes. The API change for toast.onChange and the removal of toast.configure.
Say hello to addons! What are addons? So, addons are like DLCs in video games but for react-toastify 😆. More seriously, you can think of it as utilities built around react-toastify. For example, custom theme, hooks, components etc...
The first addon that I would like to introduce is the useNotificationCenter headless hook! As the name suggests, it let you build your notification center on top of react-toastify. See for yourself 👇
https://user-images.githubusercontent.com/5574267/166549174-48422a61-ff7b-4eeb-b53f-d903db3d1595.mov
Another example using MUI.
Check the documentation for more details.
This second addon will be released later. There are a bunch of details that I need to cover and I don't want to release something too buggy. Nevertheless, I'm really excited about it and I think it's worth showcasing anyway.
I call it StackedContainer for now, it's an alternative to the ToastContainer component.
There are 2 breaking changes. The API change for toast.onChange and the removal of toast.configure.
toast.onChangeThe previous API was returning the numberOfToastDisplayed and the containerId. Honestly, this API seems to be incomplete.
For example, with the old API, if I wanted to do some logging this would be very difficult because I don't have enough data to log.
toast.onChange((numberOfToastDisplayed, containerId) => {
logger.info("nothing useful to log, ...")
})
The new API offers more possibilities. The callback will receive a ToastItem. The item provides a bunch of useful properties status, content, id, data, etc...
interface ToastItem<Data = {}> {
id: Id;
content: React.ReactNode;
theme?: Theme;
type?: TypeOptions;
isLoading?: boolean;
containerId?: Id;
data: Data;
icon?: React.ReactNode | false;
status: "added" | "removed" | "updated"
}
const unsubscribe = toast.onChange((payload: ToastItem) => {
switch (payload.status) {
case "added":
// new toast added
break;
case "updated":
// toast updated
break;
case "removed":
// toast has been removed
break;
}
});
For example, if I want to log something every time there is a new error notification, with the new API it's trivial
toast.onChange(payload => {
if(payload.status === "added" && payload.type === toast.TYPE.ERROR) {
logger.error({
createdAt: Date.now(),
content: payload.content,
data: payload.data
})
}
})
toast.configure removaltoast.configure works fine for most cases but the current implementation has one main issue. It does not work with react context because it creates a new react tree.
That being said, having 2 APIs to do the same thing is a bad thing.
Nothing published for this version
Nothing published for this version
Nothing published for this version
add deprecation notice for toast.configure.
toast.configure.toast.onChange. API for this method will change in the next major releasefix #702 autoClose duration start after the entrance animation finish
onClose now work as expected!ToastPromiseParams is now exportedThanks to @03c, @wilson-webdev, @essential-randomness for their contributions
add support for optional stages in promise #646
🚀 Features
fix text-align has not effect on content #657
fix #635 Icon on safari not displayed
Nothing published for this version
toast.promise accept function that returns a promise.
toast.promise accept function that returns a promise.Every major release introduces breaking changes but this is for the best 👌.
React-toastify has been around for 5 years(will turn five the 8 November 🎂). Since the beginning, one of the goals was to provide a library that is highly customizable and also able to work out of the box. Every major release introduces breaking changes but this is for the best 👌.
Notifications of different types (toast.info, toast.error, toast.success, toast.warning) display an icon associated with the selected type. You can also notice that the progress bar color matches the type color.
<div> <img width="280" alt="v8-icons-light" src="https://user-images.githubusercontent.com/5574267/130860515-c9cf2b64-88b4-4711-971f-9149ec497152.png"/> <img width="280" alt="v8-icons-dark" src="https://user-images.githubusercontent.com/5574267/130860512-3a165ce6-7af3-4c24-8e81-f3f5a4561841.png"/> <img width="280" alt="v8-icons-colored" src="https://user-images.githubusercontent.com/5574267/130860506-750d2799-fb73-45cf-971a-7f4f3f8f48ce.png"/> </div>
Don't be afraid 😱, if you don't like those icons you can use your own or remove them. This is what it looks like in practice.
toast("Default toast behavior is untouched, no icon to display");
toast.info("Lorem ipsum dolor"); // same as toast(message, {type: "info"});
toast.error("Lorem ipsum dolor")
toast.success("Lorem ipsum dolor")
toast.warn("Lorem ipsum dolor")
toast.error("Without icon", {
icon: false
});
toast.success("You can provide any string", {
icon: "🚀"
});
// custom icons have access to the theme and the toast type
toast.success("And of course a component of your choice", {
icon: MyIcon
});
toast.success("Even a function, given you return something that can be rendered", {
icon: ({theme, type}) => <img src="url"/>
});
//Disable icons
<ToastContainer icon={false} />
Prior to v8, toast.info, toast.error, etc... Would display respectively a blue notification, a red notification, etc... This is not the case anymore. There are 3 distinct themes: light, dark, colored. The theme can be applied globally or per notification.
//Set the theme globally
<ToastContainer theme="dark" />
// define per toast
toast.info("Display a dark notification of type info");
toast.info("Display a light notification of type info", { theme: "light" });
toast.info("Display a blue notification of type info", { theme: "colored" });
This separation will benefit theming in the future.
<img width="400" alt="v8-promise" src="https://user-images.githubusercontent.com/5574267/130862557-8d13ddf0-c6bf-4f52-968a-1d91c62b6016.png" /> <img width="400" alt="v8-promise-resolved" src="https://user-images.githubusercontent.com/5574267/130862554-652397ed-1b1e-40d4-a250-c38734ec8e5d.png" />
The library exposes a toast.promise function. Supply a promise and the notification will be updated if it resolves or fails. When the promise is pending a spinner is displayed. Again you hide it, I bet you already know how to😆.
Let's start with a simple example
const resolveAfter3Sec = new Promise(resolve => setTimeout(resolve, 3000));
toast.promise(
resolveAfter3Sec,
{
pending: 'Promise is pending',
success: 'Promise resolved 👌',
error: 'Promise rejected 🤯'
}
)
Displaying a simple message is what you would want to do in 90% of cases. But what if the message you want to display depends on the promise response, what if you want to change some options for the error notification? Rest assured, under the hood, the library uses toast.update. Thanks to this, you have full control over each notification.
const resolveWithSomeData = new Promise(resolve => setTimeout(() => resolve("world"), 3000));
toast.promise(
resolveAfter3Sec,
{
pending: 'Promise is pending',
success: {
render({data}){
return `Hello ${data}`
},
// other options
icon: "🟢",
},
error: {
render({data}){
// When the promise reject, data will contains the error
return <MyErrorComponent message={data.message} />
}
}
}
)
If you want to take care of each step yourself you can use toast.loading and update the notification yourself.
const id = toast.loading("Please wait...")
//do something else
toast.update(id, { render: "All is good", type: "success" });
One way to pass data to the notification was to use the context api or provide your own component. Starting v8 a data option is now available to make it easier.
toast(({data}) => `Hello ${data}`, {
data: "world"
})
Most of the time, users are ok with the default style, they just want to change some colors to match their brand. I think one way to improve the DX for all of us is to embrace CSS variables. That's why the library has switched to css variables! All you want is to change the color of the progress bar? No problem
:root{
// this is the default value below
--toastify-color-progress-light: linear-gradient(
to right,
#4cd964,
#5ac8fa,
#007aff,
#34aadc,
#5856d6,
#ff2d55
);
}
You can find the list of all exposed variables here
There are few breaking changes.
dark has been removed// before v8
toast("hello", {
type: "dark"
})
// toast.TYPE.DARK is no longer available
// in v8
toast("hello", {
theme: "dark"
})
// or
toast.dark("hello")
colored theme to get the same behavior as the previous versiontoast.info("hello", {
theme: "colored"
})
// or apply the theme globally
<ToastContainer theme="colored" />
info, error, warning, success// to opt-out gloablly from this behavior
<ToastContainer icon={false} />
// or per toast
toast.info("hello", {
icon: false
});
.Toastify__toast--dark {
}
.Toastify__toast--default {
}
.Toastify__toast--info {
}
.Toastify__toast--success {
}
.Toastify__toast--warning {
}
.Toastify__toast--error {
}
That's it for this release. Thank you for using react-toastify and happy coding!
Nothing published for this version
fix #572 flex layout issue(regression)
fix #561 missing declaration file
fix #560 when using limit, new toast is displayed only when exit animation is done.
Closing animation showing twice if dismiss is called after a very short time after showing the toast #559
dependency to react-transition-group has been removed #514
duration parameter has been removed from cssTransition. Css animations just works now out of the box. Check the codesanbox belowbundle size reduced from ~7k to ~5k!
remove the dependency on prop-types.
Nothing published for this version
Your coding agent can read these notes before it upgrades. Set up the MCP server →