🎉 React-Toastify allow you to add notification to your app with ease. No bullshit !
- Demo
- Installation
- Features
- Migrate from v2 to v3
- 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 hook
- Set a custom close button or simply remove it
- Add an undo option to a toast
- ✨ Define a custom enter and exit transition
- 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
- Can display a react component inside the toast !
- Don't rely on
findDOMNode
or any DOM hack - 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
- Use glamor for styling 💅
- Pause toast when the browser is not visible thanks to visibility api
- Fancy progress bar to display the remaining time
- Possibility to update a toast
The v3 rely on glamor for styling. Using css classes is still fine but you may need to replace your css classes by a glamor rule in some case.
No more css file to import !
A style helper has been added to mimic the old sass variables.
By default all toasts will inherits ToastContainer's props. Props defined on toast supersede ToastContainer's props.
import React, { Component } from 'react';
import { ToastContainer, toast } from 'react-toastify';
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';
import { css } from 'glamor';
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 !", {
position: toast.POSITION.BOTTOM_RIGHT,
className: css({
background: "black"
})
});
};
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 } from 'react-toastify';
class App extends Component {
closeAfter15 = () => toast("YOLO", { autoClose: 15000 });
closeAfter7 = () => toast("7 Kingdoms", { autoClose: 15000 })
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
{/* Some components */}
<ToastContainer autoClose={false} />
{/* Some components */}
- Disable it per toast
{/* Some components */}
toast("hello", {
autoClose: false
})
{/* Some components */}
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>
);
Use could 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. You can easily change this behavior by taking advantage of the className
option. Lets rotate the toast on update:
toast.update(this.toastId, {
render: "New Content",
type: toast.TYPE.INFO,
//Here the magic
className: css({
transform: "rotateY(360deg)",
transition: "transform 0.6s"
})
})
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 hooks on toast. Hooks 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>;
}
}
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. Simply pass
false
to closeButton
props:
- remove it by default
{/* Some components */}
<ToastContainer closeButton={false} />
{/* Some components */}
- remove it per toast
{/* Some components */}
toast("hello", {
closeButton: false
})
{/* Some components */}
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>
);
}
}
The toast rely on react-transition-group
for the enter and exit transition.
I'll use the zoom animation from animate.css. Of course, you could create the animation using glamor.
/* 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;
}
.animate{
animation-duration: 800ms;
}
- Create a transition and apply it
import React, { Component } from 'react';
import { toast } from 'react-toastify';
import Transition from 'react-transition-group/Transition';
import './style.css';
// Any transition created with react-transition-group/Transition will work !
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>;
}
}
- Or pass your transition to the ToastContainer to replace the default one.
render(){
return(
{/*Component*/}
<ToastContainer
transition={ZoomInAndOut}
/>
{/*Component*/}
);
}
You could use the style helper to replace the variable listed below:
import { style } from "react-toastify";
style({
width: "320px",
colorDefault: "#fff",
colorInfo: "#3498db",
colorSuccess: "#07bc0c",
colorWarning: "#f1c40f",
colorError: "#e74c3c",
colorProgressDefault: "linear-gradient(to right, #4cd964, #5ac8fa, #007aff, #34aadc, #5856d6, #ff2d55)",
mobile: "only screen and (max-width : 480px)",
fontFamily: "sans-serif",
zIndex: 9999,
TOP_LEFT: {
top: '1em',
left: '1em'
},
TOP_CENTER: {
top: '1em',
marginLeft: `-${320/2}px`,
left: '50%'
},
TOP_RIGHT: {
top: '1em',
right: '1em'
},
BOTTOM_LEFT: {
bottom: '1em',
left: '1em'
},
BOTTOM_CENTER: {
bottom: '1em',
marginLeft: `-${320/2}px`,
left: '50%'
},
BOTTOM_RIGHT: {
bottom: '1em',
right: '1em'
}
});
All className like props can be a css class or a glamor rule.
import React, { Component } from 'react';
import { toast } from 'react-toastify';
import { css } from 'glamor';
class Style extends Component {
notify = () => {
toast("Dark style notification with default type progress bar",{
className: css({
background: "black"
}),
bodyClassName: "grow-font-size"
});
toast("Fancy progress bar.",{
progressClassName: css({
background: "repeating-radial-gradient(circle at center, red 0, blue, green 30px)"
})
});
};
render(){
return <button onClick={this.notify}>Notify</button>;
}
}
You could define your style globally:
render(){
return(
{/*Component*/}
<ToastContainer
toastClassName="dark-toast"
progressClassName={css({
height: "2px"
})}
/>
{/*Component*/}
);
}
On mobile the toast will take all the width available.
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 int | 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 |
closeOnClick | bool | true | Dismiss toast on click |
newestOnTop | bool | false | Display newest toast on top |
className | string|glamor rule | - | Add optional classes to the container |
style | object | - | Add optional inline style to the container |
toastClassName | string|glamor rule | - | Add optional classes to the toast |
bodyClassName | string|glamor rule | - | Add optional classes to the toast body |
progressClassName | string|glamor rule | - | Add optional classes to the progress bar |
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 | ✘ | Possible keys : autoClose, type, closeButton, hideProgressBar |
- 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 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
};
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}/>
});
IE 11+ ✔ | Latest ✔ | Latest ✔ | Latest ✔ | Latest ✔ | Latest ✔ |
- 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 !
Licensed under MIT