livewire / flux

The official Livewire UI component library
https://fluxui.dev
450 stars 38 forks source link

Toasts on-top of modals aren't interactive #429

Open philippbuerger opened 1 week ago

philippbuerger commented 1 week ago

Hi, I have a flyout with a form in it. The submit triggers a toast which is shown exactly over the save button of the form. When I pressing the close button of the toast, the toast is closed but also the underlying button is triggerd so the form is submitted again and again.

philippbuerger commented 1 week ago

Just tested it with the toast rendered at another position and I noticed that the close button of the toast is not reacting. I seems that there is not click event on the toast when triggered with an open flyout / modal.

calebporzio commented 1 week ago

I was able to recreate the bug. I'll post the code here for future reference.

This is actually a bug in the way browsers handle popovers on-top of

elements that were triggered using .showModal().

I will try to raise some awareness around this issue and see if there are any plans on fixing it. I'll leave this open until I can at least confirm it's a browser bug. Thank you.

<?php

use Livewire\Volt\Component;

new class extends Component {
    public function triggerToast()
    {
        Flux::toast(text: 'I am a toast that will pop up over the submit button in the flyou modal.');
    }
};
?>

<div>
    <flux:modal.trigger name="edit-profile">
        <flux:button>Open Dialog</flux:button>
    </flux:modal.trigger>

    <flux:modal name="edit-profile" class="max-w-lg flex flex-col justify-between" variant="flyout">
        <flux:text>Press the button to trigger the toast and observe that the toast's close button doesn't work and all mouse events pass through to the underlying button.</flux:text>

        <flux:button wire:click="triggerToast">Trigger toast</flux:button>
    </flux:modal>
</div>
RyanPaiva56 commented 2 days ago

Howdy, I think I solved (solved?) this. Basically, the ::backdrop is covering the toast. If you place the toast render tag inside the modal, it works again. Basically, the toast was never unresponsive, you just couldn't click the trigger because all objects outside of the popover are inert.

There's an open issue here that discusses it:

https://github.com/whatwg/html/issues/9936

TLDR: This is working as intended. If you want to render an element while a modal is active, it needs to be within the modal. Doing this works:

<flux:modal name="edit-profile" class="max-w-lg flex flex-col justify-between" variant="flyout">
        <flux:text>Press the button to trigger the toast and observe that the toast's close button doesn't work and all mouse events pass through to the underlying button.</flux:text>

        <flux:button wire:click="triggerToast">Trigger toast</flux:button>
        <flux:toast position="left" />
</flux:modal>

But this does not:

<flux:modal name="edit-profile" class="max-w-lg flex flex-col justify-between" variant="flyout">
        <flux:text>Press the button to trigger the toast and observe that the toast's close button doesn't work and all mouse events pass through to the underlying button.</flux:text>

        <flux:button wire:click="triggerToast">Trigger toast</flux:button>
</flux:modal>
<flux:toast position="left" />

Since the toast renderer is global-ish, it might be good to be able to have more than one toast and target it by an identifier so that something like this can be done:

<flux:modal name="edit-profile" class="max-w-lg flex flex-col justify-between" variant="flyout">
        <flux:text>Press the button to trigger the toast and observe that the toast's close button doesn't work and all mouse events pass through to the underlying button.</flux:text>

        <flux:button wire:click="triggerToast" target="modal-toast">Trigger toast</flux:button>
        <flux:toast position="left" target="modal-toast" />
</flux:modal>
<flux:toast position="left" />

Or you could target nearest toast which would solve it by convention instead of configuration.

calebporzio commented 1 day ago

Thanks. I should have clarified, everything stacks correctly when nested as you've described, however, because toasts are global it's kinda hard to have the global toast provider inside your one-off modal? But yeah, good clarification.

Thanks also for listing that github issue, I'll give it a read through