Alpine.js and Livewire are two of the most popular JavaScript frameworks for Laravel. Alpine is a lightweight framework that allows you to add interactivity to your web pages without having to write a lot of code. Livewire is a framework that allows you to build interactive web pages with server-side logic.

Alpine and Livewire work well together because they complement each other’s strengths. Alpine is great for adding small bits of interactivity to your pages, while Livewire is great for building complex applications with server-side logic.

Livewire already provides some magic objects https://laravel-livewire.com/docs/2.x/alpine-js#interacting-with-livewire-from-alpine to interact with Alpine. Using these magic objects you can easily fire events on the server from javascript in a Livewire component.

But what if you want to trigger an event in the Livewire Component from outside the component?

Lets look at an example. This example will have 4 files.

  1. A broader layout file that will contain both the modal and our livewire component.
  2. A file containing the modal – this is strictly an alpine component. This is outside the livewire component – by default it can’t trigger anything server side.
  3. The livewire php file for the component
  4. The markup file for the livewire component

The files

Here is the file where our alpine component and livewire components are.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <x-modal>
    <livewire:mylivewirecomponent />
</body>
</html>

Lets assume the modal (simplified for the purpose of this blog) looks like this.

<div x-data="{ open: false, title: '', text: '', button_text: '', action_text: '', 'action': '' }"
    @modal.window="open = true; title=$event.detail.title; text=$event.detail.text; button_text=$event.detail.button_text; action_text=$event.detail.action_text; action=$event.detail.action"
    x-show="open">
    <div x-show="open" @click.away="open = false">
        <div class="modal-body">
            <h3 id="modal-title" x-text="title"></h3>
            <div>
                <p x-text="text"></p>
            </div>
        </div>
        <div class="modal-actions">
            <button type="button"
                x-show="action_text && action" x-text="action_text"
                @click="$dispatch('modalaction', {'action': action})"></button>
            <button type="button"
                @click="open = false" x-text="button_text">Cancel</button>
        </div>
    </div>
</div>

The Livewire php file

<?php

namespace App\Http\Livewire;

use Livewire\Component;

class MyLivewireComponent extends Component
{
    protected $listeners = ['modalaction' => 'handleModalAction'];

    public function handleClick()
    {
        $this->dispatchBrowserEvent('modal', ['title' => "Failure", 'text' => "Are you sure you want to stop this recovery?", 'button_text' => 'Cancel', 'action_text' => "Stop Recovery", 'action' => 'stop_recovery']);
    }

    public function handleModalAction()
    {
        var_dump('this is what you came for')
        die();
    }

    public function render()
    {
        return view('livewire.mylivewirecomponent');
    }
}

Livewire Blade File

<div x-data @modalaction.window="if ($event.detail.action == 'stop')  {$wire.handleModalAction()}">
    <button wire:click="handleClick">
        Do Action
    </button>
</div>

Lets review and tie it all together

We have an alpine component that is not connected to livewire. We have a livewire component that can trigger things server side. We want an event from the alpine component to reach out and trigger an event the livewire component is listening for.

We set up our alpine component to broadcast a javascript event on the window. Then we set up the livewire component to have a listener and then dispatch its own new event if it detects the original event from the alpine component.