π React-Toastify allow you to add notification to your app with ease. No bullshit !
- Demo
- Installation
- Features
- Migrate from v3 to v4
- Usage
- One component to rule them all
- Positioning toast
- Set autoclose delay or disable it
- Render a component
- Remove a toast programmatically
- Prevent duplicate
- Update a toast
- Define callback
- Listen for change
- Set a custom close button or simply remove it
- Add an undo option to a toast like google drive
- Replace the default transition
- Define a custom enter and exit transition
- Swipe to remove
- Le style
- Mobile
- Api
- Browser Support
- Release Notes
- Contribute
- License
$ npm install --save react-toastify
$ yarn add react-toastify
- Easy to setup for real, you can make it works in less than 10sec!
- Super easy to customize
- RTL support
- Swipe to close π
- Can display a react component inside the toast!
- Has
onOpen
andonClose
hooks. Both can access the props passed to the react component rendered inside the toast - Can remove a toast programmatically
- Define behavior per toast
Pause toast when the browser is not visible thanks to visibility APINeed to fix it- Fancy progress bar to display the remaining time
- Possibility to update a toast
Glamor has been dropped to switch back to scss due to user's feedback. You can read more about that choice if you take a look at the issues history.
- Passing glamor rule to className is still working π.
- A css file needs to be imported now.
- Toast are now draggable, you can swipe to close
- New built-in transition added
- Playground for contributor
- You may use glamorous or any other css-in-js library that relies on glamor. (Haven't been tested)
The toasts inherit ToastContainer's props. Props defined on toast supersede ToastContainer's props.
import React, { Component } from 'react';
import { ToastContainer, toast } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';
// minified version is also included
// import 'react-toastify/dist/ReactToastify.min.css';
class App extends Component {
notify = () => toast("Wow so easy !");
render(){
return (
<div>
<button onClick={this.notify}>Notify !</button>
<ToastContainer />
</div>
);
}
}
By default, all the toasts will be positionned on the top right of your browser. If a position is set on a toast, the one defined on ToastContainer will be replaced.
The following values are allowed: top-right, top-center, top-left, bottom-right, bottom-center, bottom-left
For convenience, toast expose a POSITION property to avoid any typo.
// toast.POSITION.TOP_LEFT, toast.POSITION.TOP_RIGHT, toast.POSITION.TOP_CENTER
// toast.POSITION.BOTTOM_LEFT,toast.POSITION.BOTTOM_RIGHT, toast.POSITION.BOTTOM_CENTER
import React, { Component } from 'react';
import { toast } from 'react-toastify';
class Position extends Component {
notify = () => {
toast("Default Notification !");
toast.success("Success Notification !", {
position: toast.POSITION.TOP_CENTER
});
toast.error("Error Notification !", {
position: toast.POSITION.TOP_LEFT
});
toast.warn("Warning Notification !", {
position: toast.POSITION.BOTTOM_LEFT
});
toast.info("Info Notification !", {
position: toast.POSITION.BOTTOM_CENTER
});
toast("Custom Style Notification with css class!", {
position: toast.POSITION.BOTTOM_RIGHT,
className: 'foo-bar'
});
};
render(){
return <button onClick={this.notify}>Notify</button>;
}
}
- Set the default delay
import React from 'react';
import { ToastContainer } from 'react-toastify';
// close toast after 8 seconds
const App = () => (
<ToastContainer autoClose={8000} />
);
- Set the delay per toast for more control
import React from 'react';
import { ToastContainer, toast } from 'react-toastify';
class App extends Component {
closeAfter15 = () => toast("YOLO", { autoClose: 15000 });
closeAfter7 = () => toast("7 Kingdoms", { autoClose: 7000 });
render(){
return (
<div>
<button onClick={this.closeAfter15}>Close after 15 seconds</button>
<button onClick={this.closeAfter7}>Close after 7 seconds</button>
<ToastContainer autoClose={8000} />
</div>
);
}
}
- Disable it by default
<ToastContainer autoClose={false} />
- Disable it per toast
toast("hello", {
autoClose: false
})
When you render a component, a closeToast
function is passed as a props. That way you can close the toast on user interaction for example.
import React from 'react';
import { ToastContainer, toast } from "react-toastify";
const Msg = ({ closeToast }) => (
<div>
Lorem ipsum dolor
<button>Retry</button>
<button onClick={closeToast}>Close</button>
</div>
)
const App = () => (
<div>
<button onClick={() => toast(<Msg />)}>Hello π</button>
<ToastContainer />
</div>
);
You can also render a component using a function. More or less like a "render props":
toast(({ closeToast }) => <div>Functional swag π</div>);
An id is returned each time you display a toast, use it to remove a given toast programmatically by calling toast.dismiss(id)
Without args, all the displayed toasts will be removed.
import React, { Component } from 'react';
import { toast } from 'react-toastify';
class Example extends Component {
toastId = null;
notify = () => this.toastId = toast("Lorem ipsum dolor");
dismiss = () => toast.dismiss(this.toastId);
dismissAll = () => toast.dismiss();
render(){
return (
<div>
<button onClick={this.notify}>Notify</button>
<button onClick={this.dismiss}>Dismiss</button>
<button onClick={this.dismissAll}>Dismiss All</button>
</div>
);
}
}
To prevent duplicates, you can check if a given toast is active by calling toast.isActive(id)
like the snippet below. With this approach, you can decide with more precision whether or not you want to display a toast.
import React, { Component } from 'react';
import { toast } from 'react-toastify';
class Example extends Component {
toastId = null;
notify = () => {
if (! toast.isActive(this.toastId)) {
this.toastId = toast("I cannot be duplicated !");
}
}
render(){
return (
<div>
<button onClick={this.notify}>Notify</button>
</div>
);
}
}
When you update a toast, the toast options and the content are inherited but don't worry you can update them.
import React, { Component } from 'react';
import { toast } from 'react-toastify';
class Update extends Component {
toastId = null;
notify = () => this.toastId = toast("Hello", { autoClose: false });
update = () => toast.update(this.toastId, { type: toast.TYPE.INFO, autoClose: 5000 });
render(){
return (
<div>
<button onClick={this.notify}>Notify</button>
<button onClick={this.update}>Update</button>
</div>
)
}
}
If you want to change the content it's straightforward as well. You can render any valid element including a react component. Pass your value to a render
option as follow:
// With a string
toast.update(this.toastId, {
render: "New content"
type: toast.TYPE.INFO,
autoClose: 5000
});
// Or with a component
toast.update(this.toastId, {
render: <MyComponent />
type: toast.TYPE.INFO,
autoClose: 5000
});
By default, when you update a toast, there is no transition applied. If you want to apply a transition, it can be done via the className
or the transition
option:
// with css
toast.update(this.toastId, {
render: "New Content",
type: toast.TYPE.INFO,
//Here the magic
className: 'rotateY animated'
})
// with glamor
toast.update(this.toastId, {
render: "New Content",
type: toast.TYPE.INFO,
//Here the magic
className: css({
transform: "rotateY(360deg)",
transition: "transform 0.6s"
})
})
// with transition
toast.update(this.toastId, {
render: "New Content",
type: toast.TYPE.INFO,
//Here the magic
transition: Rotate
})
If you want to inherit props from the ToastContainer
, you can reset an option by passing null.
It's particulary usefull when you remove the closeButton
from a toast and you want it back during the update:
class Update extends Component {
toastId = null;
notify = () => this.toastId = toast("Hello", {
autoClose: false,
closeButton: false // Remove the closeButton
});
update = () => toast.update(this.toastId, {
type: toast.TYPE.INFO,
autoClose: 5000,
closeButton: null // The closeButton defined on ToastContainer will be used
});
render(){
return (
<div>
<button onClick={this.notify}>Notify</button>
<button onClick={this.update}>Update</button>
</div>
)
}
}
You can define two callback on toast. They are really useful when the toast are not used only to display messages.
- onOpen is called inside componentDidMount
- onClose is called inside componentWillUnmount
import React, { Component } from 'react';
import { toast } from 'react-toastify';
class Hook extends Component {
notify = () => toast(<MyComponent foo="bar" />, {
onOpen: ({ foo }) => window.alert('I counted to infinity once then..'),
onClose: ({ foo }) => window.alert('I counted to infinity twice')
});
render(){
return <button onClick={this.notify}>Notify</button>;
}
}
If you want to know when a toast is displayed or removed, toast
expose a onChange
method:
toast.onChange( numberOfToastDisplayed => {
// Do whatever you want
});
You can pass a custom close button to the ToastContainer
to replace the default one.
closeToast
function.
You need to call it in order to close the toast.
import React, { Component } from 'react';
import { toast, ToastContainer } from 'react-toastify';
const CloseButton = ({ YouCanPassAnyProps, closeToast }) => (
<i
className="material-icons"
onClick={closeToast}
>
delete
</i>
);
class CustomClose extends Component {
notify = () => {
toast("The close button change when Chuck Norris display a toast");
};
render(){
return (
<div>
<button onClick={this.notify}>Notify</button>;
<ToastContainer closeButton={<CloseButton YouCanPassAnyProps="foo" />} />
</div>
);
}
}
import React, { Component } from 'react';
import { toast } from 'react-toastify';
// Let's use the closeButton we defined on the previous example
class CustomClose extends Component {
notify = () => {
toast("The close button change when Chuck Norris display a toast",{
closeButton: <CloseButton YouCanPassAnyProps="foo" />
});
};
render(){
return <button onClick={this.notify}>Notify</button>;
}
}
Sometimes you don't want to display a close button. It can be removed globally or per toast. Pass
false
to closeButton
props:
- remove it by default
<ToastContainer closeButton={false} />
- remove it per toast
toast("hello", {
closeButton: false
})
See it in action:
const ToastUndo = ({ id, undo, closeToast }) => {
function handleClick(){
undo(id);
closeToast();
}
return (
<div>
<h3>
Row Deleted <button onClick={handleClick}>UNDO</button>
</h3>
</div>
);
}
class App extends Component {
state = {
collection: data,
// Buffer
toRemove: []
};
// Remove the row id from the buffer
undo = id => {
this.setState({
toRemove: this.state.toRemove.filter(v => v !== id)
});
}
// Remove definetly
cleanCollection = () => this.setState({
// Return element which are not included in toRemove
collection: this.state.collection.filter(v => !this.state.toRemove.includes(v.id)),
//Cleanup the buffer
toRemove: []
});
// Remove row from render process
// then display the toast with undo action available
removeRow = e => {
const id = e.target.dataset.rowId;
this.setState({
toRemove: [...this.state.toRemove, id]
});
toast(<ToastUndo undo={this.undo} id={id} />, {
// hook will be called whent the component unmount
onClose: this.cleanCollection
});
};
renderRows() {
const { collection, toRemove } = this.state;
// Render all the element wich are not present in toRemove
// Im using data-attribute to grab the row id
return collection.filter(v => !toRemove.includes(v.id)).map(v => (
<tr key={v.id}>
<td>{v.firstName}</td>
<td>{v.lastName}</td>
<td>{v.email}</td>
<td>
<button onClick={this.removeRow} data-row-id={v.id}>
Delete
</button>
</td>
</tr>
));
}
render() {
// Dont close the toast on click
return (
<div style={styles}>
<table>
<tbody>
<tr>
<th>name</th>
<th>firstname</th>
<th>gender</th>
<th />
</tr>
{this.renderRows()}
</tbody>
</table>
<ToastContainer closeOnClick={false} />
</div>
);
}
}
There is 4 built-in transition provided:
Bounce is used by default but you can replace it by your own transition or by one of the list above:
import { Slide, Zoom, Flip, Bounce } from 'react-toastify';
<ToastContainer
transition={Slide}
/>
//...
<ToastContainer
transition={YourCustomTransition}
/>
You get the idea...
The toast relies on react-transition-group
for the enter and exit transition. Any transition built with react-transition-group should work !
I'll use the zoom animation from animate.css. Of course, you could create your own animation.
/* style.css*/
@keyframes zoomIn {
from {
opacity: 0;
transform: scale3d(.3, .3, .3);
}
50% {
opacity: 1;
}
}
.zoomIn {
animation-name: zoomIn;
}
@keyframes zoomOut {
from {
opacity: 1;
}
50% {
opacity: 0;
transform: scale3d(.3, .3, .3);
}
to {
opacity: 0;
}
}
.zoomOut {
animation-name: zoomOut;
}
/* Not needed with the cssTransition helper */
.animate {
animation-duration: 800ms;
}
The easiest way to roll your own transition is by using the cssTransition
helper. Doing so you don't need to deal with react-transition-group
. You only need to provide the enter
and the exit
class name, the transition duration
is set
to 750ms
by default but it can be overridden:
import React, { Component } from 'react';
import { toast, cssTransition } from 'react-toastify';
import './style.css';
const Zoom = cssTransition({
enter: 'zoomIn',
exit: 'zoomOut',
// default to 750ms, can be omitted
duration = 750,
});
class App extends Component {
notify = () => {
toast("ZoomIn and ZoomOut", {
transition: Zoom,
autoClose: 5000
});
};
render(){
return <button onClick={this.notify}>Notify</button>;
}
}
If you want the transition duration to be different between the enter and exit transition pass an array:
import React, { Component } from 'react';
import { toast, cssTransition } from 'react-toastify';
import './style.css';
const Zoom = cssTransition({
enter: 'zoomIn',
exit: 'zoomOut',
duration: [500, 800]
});
class App extends Component {
notify = () => {
toast("ZoomIn and ZoomOut", {
transition: Zoom,
autoClose: 5000
});
};
render(){
return <button onClick={this.notify}>Notify</button>;
}
}
Some transitions are based on the toast position. This is the case for the default one. If you pass appendPosition
to the cssTransition
helper as shown below, the current position will be appended to the enter
and exit
class name:
import React, { Component } from 'react';
import { toast, cssTransition } from 'react-toastify';
import './style.css';
const Zoom = cssTransition({
// zoomIn will become zoomIn--top-right or zoomIn--top-left and so on
enter: 'zoomIn',
// zoomIn will become zoomOut--top-right or zoomOut--top-left and so on
exit: 'zoomOut',
// default to false
appendPosition: true
});
class App extends Component {
notify = () => {
toast("ZoomIn and ZoomOut", {
transition: Zoom,
autoClose: 5000
});
};
render(){
return <button onClick={this.notify}>Notify</button>;
}
}
import React, { Component } from 'react';
import { toast } from 'react-toastify';
import Transition from 'react-transition-group/Transition';
import './style.css';
const ZoomInAndOut = ({ children, position, ...props }) => (
<Transition
{...props}
{/* Same as the animation duration */}
timeout={800}
onEnter={ node => node.classList.add('zoomIn', 'animate')}
onExit={node => {
node.classList.remove('zoomIn', 'animate');
node.classList.add('zoomOut', 'animate');
}}
>
{children}
</Transition>
);
class App extends Component {
notify = () => {
toast("ZoomIn and ZoomOut", {
transition: ZoomInAndOut,
autoClose: 5000
});
};
render(){
return <button onClick={this.notify}>Notify</button>;
}
}
You can swipe the toast to remove it:
You need to drag 80% of the toast width to remove it. This can be changed to fit your need:
- Replace the default one:
<ToastContainer draggablePercent={60}>
- Replace per toast:
toast('Hello', {
draggablePercent: 60
});
- Disable by default for all toast:
<ToastContainer draggable={false}>
- Disable per toast:
toast('Hello', {
draggable: false
});
toast("Custom style",{
className: 'black-background',
bodyClassName: "grow-font-size",
progressClassName: 'fancy-progress-bar'
});
import { css } from 'glamor';
toast("Custom style",{
className: css({
background: 'black'
}),
bodyClassName: css({
fontSize: '60px'
}),
progressClassName: css({
background: "repeating-radial-gradient(circle at center, red 0, blue, green 30px)"
})
});
<ToastContainer
className='toast-container'
toastClassName="dark-toast"
progressClassName={css({
height: "2px"
})}
/>
Your app need to support rtl content? Set the rtl props to true
:
render(){
return(
{/*Component*/}
<ToastContainer rtl />
{/*Component*/}
);
}
On mobile the toast will take all the available width.
Props | Type | Default | Description |
---|---|---|---|
position | string | top-right | One of top-right, top-center, top-left, bottom-right, bottom-center, bottom-left |
autoClose | false or number | 5000 | Delay in ms to close the toast. If set to false, the notification need to be closed manualy |
closeButton | React Element or false | - | A React Component to replace the default close button or false to hide the button |
transition | function | - | A reference to a valid react-transition-group/Transition component |
hideProgressBar | bool | false | Display or not the progress bar below the toast(remaining time) |
pauseOnHover | bool | true | Keep the timer running or not on hover |
rtl | bool | false | Support right to left content |
closeOnClick | bool | true | Dismiss toast on click |
newestOnTop | bool | false | Display newest toast on top |
className | string|object | - | Add optional classes to the container |
style | object | - | Add optional inline style to the container |
toastClassName | string|object | - | Add optional classes to the toast |
bodyClassName | string|object | - | Add optional classes to the toast body |
progressClassName | string|object | - | Add optional classes to the progress bar |
draggable | bool | true | Allow toast to be draggable |
draggablePercent | number | 80 | The percentage of the toast's width it takes for a drag to dismiss a toast(value between 0 and 100) |
All the method of toast return a toastId except dismiss
and isActive
.
The toastId can be used to remove a toast programmatically or to check if the toast is displayed.
Parameter | Type | Required | Description |
---|---|---|---|
content | string or React Element | β | Element that will be displayed |
options | object | β | Options listed below |
- Available options :
type
: Kind of notification. One of "default", "success", "info", "warning", "error". You can usetoast.TYPE.SUCCESS
and so on to avoid any typo.onOpen
: Called inside componentDidMountonClose
: Called inside componentWillUnmountautoClose
: same as ToastContainer.closeButton
: same as ToastContainer.transition
: same as ToastContainer.closeOnClick
: same as ToastContainer.hideProgressBar
: same as ToastContainer.position
: same as ToastContainerpauseOnHover
: same as ToastContainerclassName
: same as ToastContainer toastClassNamebodyClassName
: same as ToastContainerprogressClassName
: same as ToastContainerdraggable
: same as ToastContainerdraggablePercent
: same as ToastContainerrender
: string or React Element, only available when calling update
const Img = ({ src }) => <div><img width={48} src={src} /></div>;
const options = {
onOpen: props => console.log(props.foo),
onClose: props => console.log(props.foo),
autoClose: 6000,
closeButton: <FontAwesomeCloseButton />,
type: toast.TYPE.INFO,
hideProgressBar: false,
position: toast.POSITION.TOP_LEFT,
pauseOnHover: true,
transition: MyCustomTransition,
// and so on ...
};
const toastId = toast(<Img foo={bar}/>, options) // default, type: 'default'
toast(({ closeToast }) => <div>Render props like</div>, options);
toast.success("Hello", options) // add type: 'success' to options
toast.info("World", options) // add type: 'info' to options
toast.warn(<Img />, options) // add type: 'warning' to options
toast.error(<Img />, options) // add type: 'error' to options
toast.dismiss() // Remove all toasts !
toast.dismiss(toastId) // Remove given toast
toast.isActive(toastId) //Check if a toast is displayed or not
toast.update(toastId, {
type: toast.TYPE.INFO,
render: <Img foo={bar}/>
});
Parameter | Type | Required | Default | Description |
---|---|---|---|---|
enter | string | β | - | The class name that will be used when the toast enter |
exit | string | β | - | The class name that will be used when the toast exit |
duration | number| Array | β | 750 | The transition duration in ms. |
appendPosition | bool | β | false | Append or not the position to the class name: yourClassName--top-right , yourClassName--bottom-left ... |
import { cssTransition } from 'react-toastify';
const Zoom = cssTransition({
enter: 'zoomIn',
exit: 'zoomOut',
duration: 750,
appendPosition: false
});
const Zoom = cssTransition({
enter: 'zoomIn',
exit: 'zoomOut',
duration: [500, 600],
appendPosition: false
});
IE 11+ β | Latest β | Latest β | Latest β | Latest β | Latest β |
- Draggable prop can be updated, more details here
- Fix issue when passing glamor className. More details
pauseOnVisibility
has been disabled until I found a fix. The api is too much unstable π©.
- Switch back to css
- Added built-in transition
- Added playground for contributor
- Upgrade to webpack 4
- Draggable π
- Fix position on mobile
- Fix exit animation bug
- Fix rtl on mobile
- Add
rtl
props to support right to left content.
- Add
fontFamily
to typescript definition
toast.update
run now at the end of the call stack. For more details, check issue #135
- Clean animation on entered. This was preventing any update transition to works.
- Fix height issue #124
- Update typescript definition
- Better accessibility, relate to issue #121
- Reviewed exit animation. No more clipping.
- Add comment to typescript definition.
- Fix typescript definition. Relate to issue #110
- Allow "render props" rendering. Relate to issue #106
- Can set fontFamily via the style helper. Relate to issue #107
- Can override position default values via style helper. Realte to issue #108
- Fix issue #103 for real...
- Fix issue #104 Incorrect TS definition for
toast.dismiss
- Fix issue #103
- Add ability to update an existing toast
- Allow to define the zIndex via the style helper
- Get rid of all inline style
- Switched to styled component with glamor
- Added style helper to replace sass variables
- Test suite improved
- Typescript definition improved
- Fix issue #71
- Sass variables are now namespaced
- Can now use sass variable default thanks to vikpe
- Test suites improved
- Fix broken typescript dependencies
- Added typescript definition
- Toast will pause when page is not visible thanks to page visibility api.
- Previous version was breaking compatibility with react < 16
- Remove toast from react dom when not displayed. Because of that the
onClose
callback on the toast was never called. Relate to issue #50
- Can set a custom transition when the toat enter and exit the screen β¨
- Upgrade to react v16
- Upgrade to enzyme v3
- Switched to react-app preset for eslint
- Upgrade to webpack v3
- Upgrade to react-transition-group v2
This version may introduce breaking changes due to redesign. My apologies.
But, it brings a lots of new and exciting features !
- The default design has been reviewed. The component is now usable out of the box without the need to touch the css. Relate to issue #28
- The toast timer can keep running on hover. issue #33
- Added a possibility to check if a given toast is displayed or not. By using that method we can prevent duplicate. issue #3
- Can decide to close the toast on click
- Can show newest toast on top
- Can define additionnal className for toastissue #21
- Much more mobile ready than the past
- The space in of left boxes from window & right boxes from window is different.issue #25
- Partial support of ie11. I still need to fix the animation but I need a computer with ie11 for that xD issue #26
- Toast can now be positioned individually !
- Can now remove a toast programmatically. When you display a toast, the function return a toastId. You can use it
as follow to remove a given toast
toast.dismiss(toastId)
- If the container is not mounted, the notification will be added to a queue and dispatched as soon as the container is mounted. For more details check issue #4
- Added --no-idents flag to cssnano to avoid animation name collision with others libs.
- Tests are no longer transpiled
- That version does not bring any features but it brings tests made with the amazing jest and aslo Travis CI integration.
- React and react-dom are now peer dependencies
- Don't try to pass down the props when we render a string like so :
toast(<div>hello</div>)
- Fixed the test to check if the toast can be rendered
- React v16 ready : moving to prop-types and react-transition-group
- Internal rewrite of components. The implementation wasn't bad but it wasn't good either. A better props validation has been added has well.
- Removed useless dependencies. I was using the Object.values polyfill when a one line forEach can do the same is my case.
- Now I believe it's even easier to style the components. The sass sources files are now included when you install the package via yarn or npm
- The default close button has been replaced.
- A progress bar is now visible to track the remaining time before the notification is closed. Of course if you don't like it, you are free to disable it.
- You can choose to display a close button or not.
- Event pointer is set to none to avoid losing pointer events on everything beneath the toast container when no toast are displayed
- The
closeToast
callback is also passed down to your component.
- PropTypes package update
- Dead code elimination
- Possibility to use a custom close button. Check the api docs of ToastContainer and toast.
I was storing react component into state which is a bad practice. What should Go in State This is no more the case now. The separation of concern between the data and the view is respected.
- Was calling cloneElement on undefined which cause your console bleed. See issue #2
- Added Object.values polyfill otherwise won't work with IE or EDGE. I β₯ IE.
- OnClose and OnOpen can access all the props passed to the component. Before only the props passed using toast options were accessible
- Passing prop using toast option will be removed at the next release. It doesn't make sense to keep both way to pass props. Use the react way instead
- Added onOpen callback
- Added onClose callback
Show your β€οΈ and support by giving a β. Any suggestions and pull request are welcome !
Try the playground:
npm start
Licensed under MIT