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

Merklin's avatar

Show bootstrap toast on Livewire event?

Hi all. I am trying to show a bootstrap toast on dispatched event from Livewire. This is my code:

<div x-data
     x-init="@this.on('updated', () => {
        var element = document.getElementById('liveToast');
        var myToast = new bootstrap.Toast(element);
        myToast.show();
     })"
    class="toast-container position-fixed top-0 end-0 p-3">
    <div class="toast bg-secondary " id="liveToast" role="alert" aria-live="assertive" aria-atomic="true">
        <div class="toast-body text-white d-flex justify-content-between">
            <span>Hello, world! This is a toast message.</span>
            <button type="button" class="btn-close" data-bs-dismiss="toast" aria-label="Close"></button>
        </div>
    </div>
</div>

And I am calling it in my blade file as a component <x-toasts.warning/>

I can confirm that the event is fired, but still, the toast doesn't show up. I'm not good at javascript/alpinejs so any help is appreciated.

0 likes
3 replies
Braunson's avatar

Do you get any JS errors? Have you tried confirming that the event is called (i.e. adding an alert or console.log inside the init?) Here's how I would implement it.

1 Create a Bootstrap Toast in your HTML:

Firstly create an invisible Bootstrap Toast in your HTML (This is your toast template that will become visible upon triggering):

<div id="liveToast" class="toast" role="alert" aria-live="assertive" aria-atomic="true">
  <div class="toast-header">
    <strong class="me-auto">Bootstrap Toast</strong>
    <button type="button" class="btn-close" data-bs-dismiss="toast" aria-label="Close"></button>
  </div>
  <div class="toast-body">
    Your Livewire component has been updated!
  </div>
</div>

2 Set up an Alpine.js component in your blade file:

Just as before, create an Alpine.js component that listens to the 'open-toast' event:

<div x-data="{}" @open-toast.window="
    var element = document.getElementById('liveToast');
    var toast = new bootstrap.Toast(element);
    toast.show();
"></div>

In the above example, the Alpine component is empty (x-data="{}"), and it simply exists to listen for the 'open-toast' event. This event triggers whenever we want to show the toast.

3 Listen to the 'updated' hook in your Livewire component: Again, you'd listen for the 'updated' hook event inside your Livewire component:

class YourComponent extends Component
{
    protected $listeners = ['updated' => 'showToast'];

    // ...

    public function showToast($field)
    {
        $this->dispatchBrowserEvent('open-toast');
    }

    // ...

    // Rest of your Livewire component
}

So, now whenever any livewire property updates, the 'updated' event fires, calling showToast method which dispatches a browser event called open-toast. This event is listened by the Alpine.js component that triggers the Bootstrap Toast defined earlier. This way you achieve showing the toast whenever a livewire property updates.

Merklin's avatar

@Braunson

  1. No JS errors and I can confirm that the event si triggered. I have this code in the component:
public function markAsRead($notificationId): void
    {

        $notification = UserNotification::find($notificationId);
        $notification->read_at = now();
        $notification->save();

        $this->dispatch('refresh')->to('TopBar');
        $this->dispatch('refresh')->to('Sidenav');
        $this->dispatch('updated');
    }
  1. With your code I get an error:
Alpine Expression Error: Unexpected token 'var'

Expression: "
     var element = document.getElementById('liveToast');
     var toast = new bootstrap.Toast(element);
     toast.show();"

If I replace var with let or const, there are no errors, but the toast doesn't show in all cases.

  1. Using a button and script it shows, but I want to it show upon an event. This is the regular script for a button:
<script>
document.addEventListener("DOMContentLoaded", function(){
    var btn = document.getElementById("liveToastBtn");
    var element = document.getElementById("liveToast");

    // Create toast instance
    var myToast = new bootstrap.Toast(element);

    btn.addEventListener("click", function(){
        myToast.show();
    });
});
</script>
Merklin's avatar

After some tests, I've found out that I have to add some delay to give Livewire enough time to process the event and update the DOM before showing the toast. The working code is like this:

<div x-data
     x-init="@this.on('updated', event => {
         var element = document.getElementById('liveToast');
         setTimeout(function() {
            const myToast = new bootstrap.Toast(element);
            console.log('updated');
            myToast.show();
         }, 100);
     })">
    <div class="toast-container position-fixed top-0 end-0 p-3">
        <div class="toast bg-secondary" id="liveToast" data-bs-autohide="false">
            <div class="toast-body text-white d-flex justify-content-between">
                <span>Hello, world! This is a toast message.</span>
                <button type="button" class="btn-close" data-bs-dismiss="toast" aria-label="Close"></button>
            </div>
        </div>
    </div>
</div>

Please or to participate in this conversation.