DEV Community

Mateusz Cholewka
Mateusz Cholewka

Posted on • Updated on

Alpine.js modal transition in Livewire the missing manual part

For the last few days, I'm learning how to use the Laravel Livewire framework. I'm really impressed with how well it works, and how fast we can develop working applications using Livewire along with Tailwind CSS. It's a great option for someone who wants to start his own startup as a one-man army. Only you need to know is PHP or more precisely Laravel and some HTML / CSS.

Not everything is possible over the wire

HTML over the wire (which is the main concept behind Livewire) is very powerful, but not everything is possible to do using only on the backend. Some UX features require to use of the frontend API.

One of the things that are not possible using only Livewire is transition animations of HTML elements. There was functionality wire:transition before the first release of Livewire, but it has been removed in the final release for some reason.

When you try to look for a Livewire transition in livewire/livewire GitHub issues, almost all of them contain the information, that there are no attributes like wire:transition and that Livewire supports Alpine.js transitions. That's fine, but there are no working examples, and some GitHub users were a bit confused about that.

The solution

tl:dr If you want just to copy and paste the working solution, please go ahead 😉
I prepared a working modal component in a gist: https://gist.github.com/mtk3d/699502a70ee9af1cd412ddcb805e20da


First let's create a basic modal in Livewire, just using blade @if statement.

class Modal extends Component
{
    public string $content;
    public bool $show;

    public function mount(): void
    {
        $this->content = 'Modal content';
    }

    public function render()
    {
        return view('livewire.modal');
    }
}
Enter fullscreen mode Exit fullscreen mode

And the blade template:

<div>
    <button wire:click="$set('show', true)">
        Open
    </button>
    @if($show)
    <div>
        <div>{{ $content }}</div>
        <button wire:click="$set('show', false)">
            Close
        </button>
     </div>
    @endif
</div>
Enter fullscreen mode Exit fullscreen mode

Of course instead of using $set() you can set up PHP open/close methods in the component and call them using wire:click.

After refreshing the page, it should works like this one:
Image description

Ok, and now, let's modify this component, to work with Alpine.js transitions. You need only to change the template part:

<div x-data>
    <button wire:click="$set('show', true)">
        Open
    </button>
    <div x-cloak
        x-show="$wire.show"
        x-transition.opacity.duration.500ms
    >
        <div>{{ $content }}</div>
        <button wire:click="$set('show', false)">
            Close
        </button>
    </div>
</div>
Enter fullscreen mode Exit fullscreen mode

First, in the main component element (div in this example) add the x-data attribute. That will inform Alpine.js that this component contains some attributes to process.

Next remove @if statement and add x-show and x-transition attributes to the modal element. As a parameter for x-show you can use the value of $show property from component, using JS $wire proxy object.

Do not forget about the x-cloak attribute, and the CSS definition for it. x-cloak is the attribute that prevents hidden elements from blinking before the Alpine.js is loaded. By default, it hides the element by CSS, and then it's removed by Alpine.js on load.

Add to your CSS file:

[x-cloak] { display: none !important; }
Enter fullscreen mode Exit fullscreen mode

The rest of the code is the same as before. Now our modal should work like this:
Image description

And that's it, we have working Alpine.js transitions in Livewire 😁

Discussion (0)