Movatterモバイル変換


[0]ホーム

URL:


Skip to content
DEV Community
Log in Create account

DEV Community

Cover image for React-toastify v11 - finally easy to customize
Fadi Khadra
Fadi Khadra

Posted on

     

React-toastify v11 - finally easy to customize

Never heard of react-toastify before? Go check thedemo

What is new in v11

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.

customization

No need to import the css file anymore

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';functionApp(){constnotify=()=>toast("Wow so easy !");return(<div><buttononClick={notify}>Notify !</button><ToastContainer/></div>);}
Enter fullscreen modeExit fullscreen mode

Easy customization!

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 🤯!

customization

Head tostackblitz 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.

noti-struct

  • Toastify__toast-body and its child are now completely gone.
  • TheCloseButton 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);
Enter fullscreen modeExit fullscreen mode

Custom progress bar

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 likeautoClose,pauseOnHover,pauseOnFocusLoss, or even a controlled progress bar—it just works seamlessly for you.

custom-progress-bar

Here is a small gist.

functionApp(){constnotify=()=>{toast(CustomComponent,{autoClose:8000,// removes the built-in progress barcustomProgressBar:true});};return(<div><buttononClick={notify}>notify</button><ToastContainer/></div>);}// isPaused is now available in your component// it tells you when to pause the animation: pauseOnHover, pauseOnFocusLoss etc...functionCustomComponent({isPaused,closeToast}:ToastContentProps){return(<div><span>Hello</span><MyCustomProgressBarisPaused={isPaused}onAnimationEnd={()=>closeToast()}/></div>);}
Enter fullscreen modeExit fullscreen mode

Head tostackblitz for a live example.

Accessibility and keyboard navigation

ToastContainer andtoast accept anariaLabel prop(finally...). This is quite helpful for screen readers and also for testing.
For example, in cypress you could docy.findByRole("alert", {name: "the aria label you specified"}).

toast("hello",{ariaLabel:"something"})
Enter fullscreen modeExit fullscreen mode

If a notification is visible and the user pressesalt+t it will focus on the first notification allowing the user to useTab to navigate through the different elements within the notification.

ThehotKeys can be changed of course.

// focus when user presses ⌘ + FconstmatchShortcut=(e:KeyboardEvent)=>e.metaKey&&e.key==='f'<ToastContainerhotKeys={matchShortcut}ariaLabel="Notifications ⌘ + F"/>
Enter fullscreen modeExit fullscreen mode

Notification removal reason with onClose callback

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 theonClose callback is nowonClose(reason?: boolean | string) => void.

When the user closes the notification, thereason argument is equal totrue. In the example below, I've named my argument
removedByUser to make the intent clear.

toast("hello",{onClose(removedByUser){if(removedByUser){// do somethingreturn}// auto close do something else}})
Enter fullscreen modeExit fullscreen mode

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";functionCustomNotification({closeToast}:ToastContentProps){return<div>      You received a new message<buttononClick={()=>closeToast("reply")}>Reply</button><buttononClick={()=>closeToast("ignore")}>Ignore</button></div>}toast(CustomNotification,{onClose(reason){switch(reason){case"reply":// navigate to reply page for example or open a dialogcase"ignore":// tell the other user that she/he was ghosted xDdefault:// 🤷‍♂️}}})
Enter fullscreen modeExit fullscreen mode

💥 Breaking Changes

useToastContainer and useToast no longer exposed

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.

onClose and onOpen no longer receive children props

In hindsight, I should never have done this. The feature is practically not used. Below the new signature for each callback:

  • onOpen: () => void
  • onClose: (reason?: boolean | string) => void

Styling

  • react-toastify/dist/ReactToastify.minimal.css has been removed.
  • Scss is out of the picture now. The library uses good old css.
  • bodyClassName andbodyStyle 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.
  • The css classToastify__toast-body and its direct child have been removed.noti-struct

🐞 Bug Fixes

  • add support for react19#1177#1185
  • reexport CloseButtonProps#1165
  • fix newestOnTop for real this time#1176
  • no longer throw this ugly error: Cannot set properties of undefined (setting 'toggle')#1170
  • onClose callback is no longer delayed until the exit animation completes#1179

🔮What's next?

I'm gradually rewriting part of the documentation. I've created acollection on stackblitz, this way you can find all the examples in one place. I'll keep adding more examples as I go.

Screenshot 2024-12-16 at 09 50 48

Top comments(0)

Subscribe
pic
Create template

Templates let you quickly answer FAQs or store snippets for re-use.

Dismiss

Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment'spermalink.

For further actions, you may consider blocking this person and/orreporting abuse

  • Location
    ::1
  • Joined

More fromFadi Khadra

DEV Community

We're a place where coders share, stay up-to-date and grow their careers.

Log in Create account

[8]ページ先頭

©2009-2025 Movatter.jp