Alpine.js modal transition in Livewire the missing manual part
Tags: php, laravel, javascript, livewire
Published: 2022-02-13 19:51:45

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.

```PHP
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');
    }
}
```

And the blade template:

```HTML
<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>
```

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6257x55ecfcx1ew7ho1g.gif)

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

```HTML
<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>
```

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](https://laravel-livewire.com/docs/2.x/alpine-js#interacting-with-livewire-from-alpine).

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:

```CSS
[x-cloak] { display: none !important; }
```

The rest of the code is the same as before. Now our modal should work like this:
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sxuazni9a679ke9g2wi8.gif)

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