fkhadra / react-toastify

React notification made easy 🚀 !
https://fkhadra.github.io/react-toastify/introduction
MIT License
12.58k stars 692 forks source link

Popover API and top-layer support #959

Open Link2Twenty opened 1 year ago

Link2Twenty commented 1 year ago

Do you want to request a feature or report a bug? Feature request

What is the current behavior? Toasts appear over the top of the base layer

What is the expected behavior? Toasts should be elevated to the top layer where possible

With the new Popover API on the horizon it might be worth looking into allowing toasts to be placed in the top-layer. This will prevent toasts from being behind dialogs and popover elements which, I imagine, will become a problem in the future.

Related issues Feature Request: Top Layer Stack Management API to get top layer elements A popover on top of a modal dialog should be interactable

andelkocvjetkovic commented 1 year ago

I already had this in <dialog></dialog>. I solved it with multiple containers, but it would be great if the library handled this for us.

Link2Twenty commented 6 months ago

Just a gentle prompt that popover will be in all browsers when Firefox 126 is released which is scheduled for 2024-05-14.

lcoronelp commented 4 months ago

Currently, I am encountering this problem in a production project.

I am looking for solutions and temporary workarounds until the library handles it on its own.

Link2Twenty commented 4 months ago

Unfortunately there's no nice way to keep things in the topmost position. I imagine the whole toast container can be promoted to the top layer but everytime something new is promoted the toast container will need to be removed and re-promoted.

https://x.com/bramus/status/1764979592077381641

lcoronelp commented 4 months ago

I have tried to play around with this a bit and have something that, although not optimal, makes it appear above other popover or dialog. However, I still have a serious problem to solve that I will explain at the end.

I will try to provide to you a example code ASAP, but by now i can explain it.

I created a React wrapper component of the <ToastContainer> that is a <div> with the popover property set to manual.

In the wrapper, I use the toast.OnChange event to keep track of the identifiers of the toasts that are added and removed (side note: I don't know if exists but I would love to have a property similar to status that tells me how many toasts currently exist, so I don't have to track it externally with status added - removed).

If the array of ids has content (there are toasts to show), I trigger showPopover and otherwise, i trigger the hidePopover.

Up to this point, it works wonderfully to appear above other <dialog> or elements with popover that already exist in the top-layer. But, what happens if while the toasts are being displayed, another <dialog> or elements with popover open? The new element overlays the toast wrapper and hides it (partially or completely)! Just as @Link2Twenty mentioned in the previous comment.

"Solution": As @Link2Twenty indicated, reattaching the wrapper containing the <ToastContainer> every time a <dialog> or element with popover opens, is not optimal, but I don't see another option!

For this, I have a function that does the hidePopover of the wrapper and immediately after, in the next frame, I execute showPopover again. Visually, the trick is almost unnoticeable.

But this function has to be executed every time a <dialog> or elements with popover open...

For popover, it's a simple (although not optimal) listener to the beforetoggle or toggle event for the entire document (although it has to be done in the capturing phase since it doesn't have a bubbling phase).

For the <dialog>, oh, surprise! There is a close event but no open event! So, with all the disgust in the world, the only thing I found was to overwrite the showModal method of the HTMLDialogElement prototype (ugh).

Well, after this suffering, everything looks fine. Every time I open another <dialog> or element with popover while I have toasts on screen, my wrapper with the <ToastContainer> always overlays! Success!

Not so fast, it looks good, but it does not work well. What happens when I want to close the toast?

If the wrapper is an element with popover, because the element that loads it is a <dialog> and thanks to this link everything that is not within the subsequently opened <dialog> becomes inert (yes! even if it's in a higher layer of the top-layer!).

And in the same way, if the wrapper is a <dialog> (this is what I tried later), for exactly the same reason, I can't click anywhere else but the actions inside the toasts, so the idea of it being a non-blocking message is completely lost.

Therefore, I have reached a dead end where I see several drawbacks:

In my particular case, the components I use are fully developed by my team, so we can ban the use of <dialog> and make everything popover elements, and thus have the "solution" to the problem using this workaround. However, I see the future of react-toastify in danger when the use of <dialog> begins to generalize within various component libraries!

It occurs to me that we could campaign, among all those interested, to reach the W3C and WHATWG with this problem, proposing several future changes to the standards to avoid this behavior and give the developer more control over these new top-layer elements!

Changes like:

I apologize if I have made any mistakes in my assessments or if I have not considered any options or possibilities. If anyone has any ideas, please help!

Link2Twenty commented 4 months ago

@lcoronelp I totally missed the inert issue 😕

I have already started a proposal to allow listening for top layer promotion and being able to change the render order of things in the top layer stack over on WHATWG.

If you like you can raise your concern about inert over there too.

OliverJAsh commented 3 months ago

@lcoronelp

In my particular case, the components I use are fully developed by my team, so we can ban the use of <dialog> and make everything popover elements,

Did you find a way to simulate a modal using popovers, especially making the background inert? I ask because we are running into the same limitation at Unsplash, so I'm considering a similar workaround to the one you describe.