Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

longestdrive's avatar

Livewire/Alpine issue with a click button fails after a couple of clicks

Hi I'm having a few behaviour issues with Livewire and not sure how to dig into the issues and fix...

The one for now relates to a button on a page:

I have a click button on a page to test out flash messaging in a livewire component. Click on the button and a flash message appears.

On the first click it works as expected and the flash message appears, eventually times out and disappears as expected.

On the second click it appears but then doesn't disappear. I also had another hidden element on the same page which on the second click appeared - unexpectedly and stayed open.

This is the button:

<button type="button"
                wire:click="flash()"
                class="block p-block py-2 px-2 hover:rounded-sm hover:bg-red-900 text-red-600 flex items-center">
            <span class="px-1 py-2">Flash</span>
        </button>

This is the method it calls:

public function flash()
    {
        session()->flash('success', 'Test flash message.');
        $this->dispatch('flash-message');
    }

this is how the component is used:

<x-common.flash title="Success" :message="session('success')" type="success" />

and this is the component:

<div x-data="{show: true}" x-init="setTimeout(() => show = false, 5000)" x-show="show"
     x-transition:enter="transition ease-out duration-500"
     x-transition:enter-start="opacity-0"
     x-transition:enter-end="opacity-100"
     x-transition:leave="transition ease-in duration-500"
     x-transition:leave-start="opacity-100"
     x-transition:leave-end="opacity-0"
     @flash-message.window="show = false; setTimeout(() => show = true, 0)"
>
    <div class="{{ $level[$type] }} border-l-4 p-4" role="alert">
        <div class="flex justify-between">
            <p class="font-bold">{{ $title }}</p>
            <div @click="show = false" class="cursor-pointer">X</div>
        </div>
        <p>{{ $message }}</p>
    </div>
</div>

I've tried some googling and it suggested the show value was not being reset so created a window event to reset.

I'm not sure how to debug the show values and work out why this happens

Any ideas on where to start?

0 likes
4 replies
LaryAI's avatar
Level 58

The issue you're experiencing seems to be related to the timing and resetting of the show variable in your Alpine.js component. When you click the button, the flash() method is called, which dispatches a flash-message event. This event is supposed to reset the show variable, but it seems like the logic might not be working as expected on subsequent clicks.

Here's a step-by-step approach to address the issue:

  1. Ensure Event Dispatching: Make sure that the flash-message event is being dispatched correctly. You can add a console log in your Livewire component to verify this.

  2. Alpine.js Logic: The logic for resetting show might be causing the issue. The @flash-message.window event handler sets show to false and then immediately to true. This might not be giving enough time for the transition to complete. Instead, you can try resetting show after a slight delay.

  3. Debugging: Add some console logs to track the value of show and see how it changes over time.

Here's a revised version of your Alpine.js component:

<div x-data="{ show: false }" 
     x-init="$watch('show', value => { if (value) setTimeout(() => show = false, 5000) })"
     x-show="show"
     x-transition:enter="transition ease-out duration-500"
     x-transition:enter-start="opacity-0"
     x-transition:enter-end="opacity-100"
     x-transition:leave="transition ease-in duration-500"
     x-transition:leave-start="opacity-100"
     x-transition:leave-end="opacity-0"
     @flash-message.window="show = true; console.log('Flash message triggered');"
>
    <div class="{{ $level[$type] }} border-l-4 p-4" role="alert">
        <div class="flex justify-between">
            <p class="font-bold">{{ $title }}</p>
            <div @click="show = false" class="cursor-pointer">X</div>
        </div>
        <p>{{ $message }}</p>
    </div>
</div>

Key Changes:

  • x-init: Use $watch to monitor changes to show. When show becomes true, start the timeout to set it back to false.
  • Event Handler: The @flash-message.window event now sets show to true directly, and a console log is added for debugging.

Additional Tips:

  • Console Logs: Use console.log to track the flow of your application and see when events are triggered and how variables change.
  • Livewire Debugging: Ensure that Livewire is correctly dispatching events by checking the browser's console for any errors.

By following these steps, you should be able to resolve the issue with the flash message not disappearing on subsequent clicks.

longestdrive's avatar

Sadly not fixed yet: I've added the watch but the value doesn't appear in the console. The parent component in which I've added the flash method is a Livewire table. When I click on the button - the Livewire component now triggers a refresh for some reason and I can see the table being resorted to it's default. Also when I click the button the first time I don't get the window event being fired but I do on subsequent clicks. So the first click it works as expected - it timeouts and then hides, the table also refreshes. The second click it then shows again but doesn't time out and no changes to other components

is x-init only triggered on the first render?

Unclear how to resolve - are there alternatives to flash messages that work? :(

Snapey's avatar

x-init is only performed when the code is first rendered on the page. You need state changes triggered from an event that alpine can hear. Dont assume that Livewire will re-render the component

1 like
longestdrive's avatar

@snapey Thanks for the response about the component - can I check my understanding with you on lifecycles? :) I've gone back to try and understand what's happening here in trying to display a flash message. What I failed to include above is that the component is embedded within an if statement: @if(session('success')) <component /> @endif

So - on page load the session is not set so the component doesn't get rendered. On clicking the button - the method within the livewire class sets the session - session now has a value and then the flash message is rendered- The livewire component is checking this. In rendering the component - X-init is triggered - the message is shown and eventually changed to hide following the timeout.

On the first display - I don't see the console.log displaying my debug message "Flash Message Triggered". I've also added a $watch to the show variable which also does not appear - on that first click.

On the second click the flash message is shown - the timeout is not set as X-init is not triggered - I can then see the debug messages for the component together with the $watch.

The flash message does not hide (as the timeout is not being set) - each subsequent click I can see the debug messages and $watch.

So - not displaying the debug messages first time - is that expected behaviour?

I have previously tried to unset the session on the hope that then resetting would render a fresh component but that failed to work - what approach is needed to hide the flash message on subsequent clicks?

Clearing the session value - does livewire completely remove the component or is this held/hidden in a state somewhere and so not fully refreshed?

Sorry for all the questions - trying to learn :)

Thanks

Please or to participate in this conversation.