UniTue's avatar

FadeIn FadeOut Elements with Livewire / Tailwind and AlpineJS

Hey there,

I'm using Laravel Livewire with Tailwind and AlpineJS.

I have a SPA in which the user can fill out different fields. Depending on the filled out fields i want to show / hide some more controls.

Right now I got this working with Livewire pretty well, by just using:

@if ($predictions)
Show what i want to show
@endif

As it comes to some animations like a little fade-in or fade-out, I don't find a clean and easy solution right now. At the moment I use AlpineJS to realize an animation, by using a Component (in my case: transition.blade.php)

@props(['open'])
<div x-cloak
    x-show="open"
    x-transition:enter="transition ease-out duration-300"
    x-transition:enter-start="opacity-0 scale-90"
    x-transition:enter-end="opacity-100 scale-100"
    x-transition:leave="transition ease-in duration-300"
    x-transition:leave-start="opacity-100 scale-100"
    x-transition:leave-end="opacity-0 scale-90">
   {{ $slot }}
</div>

This workes out, but it doesn't really look pretty, see my livewire component:

                       <div x-data="{ open: @entangle('search').defer }">
                       <x-elements.button id="next-btn" action="searchLocation" showIf="searchLocation"
                                                text="next"></x-elements.button>
                       </div>

My button component:

<x-transition>
   <button id="{{ $id }}" wire:click="{{$action}}"
           autofocus
           @if(isset($hidden)) hidden @endif>
       {{$text}}
   </button>
</x-transition>

This looks pretty awkward to me, for just getting a little animation on my button when it gets displayed... maybe there is a cleaner solution for this? (Question 1)

So the next thing was to set an focus on that button, when it gets displayed. For the moment, I'm using a Timeout in Javascript (forgive me for this one.. that's why I'm writing here):

                   setTimeout(function() {
                       document.getElementById("next-btn").focus();
                   }, 1000);

I couldn't get the problem solved with AlpineJS i tried a lot of different paths.. none of them worked.

How can I get a focus on the button, when a Condition in Livewire gets true? (Question 2)

So I want to know, how do u animate: fade-in / fade-out on elements depending on specific livewire variables?

Thank you in advance.

0 likes
4 replies
LaryAI's avatar
Level 58

To achieve fade-in and fade-out animations on elements depending on specific Livewire variables, you can use AlpineJS along with Tailwind CSS. Here's a step-by-step solution:

  1. Install AlpineJS and Tailwind CSS if you haven't already. You can use npm or yarn to install them:
npm install alpinejs
npm install tailwindcss
  1. In your Livewire component's blade file, add the necessary AlpineJS and Tailwind CSS scripts:
@push('scripts')
    <script src="{{ asset('js/alpine.js') }}"></script>
@endpush

@push('styles')
    <link href="{{ asset('css/tailwind.css') }}" rel="stylesheet">
@endpush

Make sure to adjust the paths to the AlpineJS and Tailwind CSS files based on your project's setup.

  1. Add the fade-in and fade-out classes to the elements you want to animate. You can use the x-show directive provided by AlpineJS to conditionally show or hide the elements based on Livewire variables. Here's an example:
<div x-data="{ showElement: @entangle('predictions') }">
    <div x-show="showElement" x-transition:enter="transition ease-out duration-300" x-transition:enter-start="opacity-0" x-transition:enter-end="opacity-100" x-transition:leave="transition ease-in duration-300" x-transition:leave-start="opacity-100" x-transition:leave-end="opacity-0">
        <!-- Element to fade in -->
    </div>
</div>

In this example, the showElement variable is entangled with the predictions Livewire property. When predictions is truthy, the element will fade in. When predictions becomes falsy, the element will fade out.

  1. To set focus on a button when a condition in Livewire becomes true, you can use the x-ref directive provided by AlpineJS. Here's an example:
<div x-data="{ showButton: @entangle('searchLocation') }">
    <button x-ref="nextButton" x-show="showButton" x-transition:enter="transition ease-out duration-300" x-transition:enter-start="opacity-0" x-transition:enter-end="opacity-100" x-transition:leave="transition ease-in duration-300" x-transition:leave-start="opacity-100" x-transition:leave-end="opacity-0">
        Next
    </button>
</div>

@push('scripts')
    <script>
        document.addEventListener('livewire:load', function () {
            Livewire.hook('afterDomUpdate', () => {
                if (@this.searchLocation) {
                    const nextButton = document.getElementById('next-btn');
                    nextButton.focus();
                }
            });
        });
    </script>
@endpush

In this example, the showButton variable is entangled with the searchLocation Livewire property. When searchLocation becomes truthy, the button will fade in and receive focus.

Note: Make sure to adjust the Livewire property names (predictions and searchLocation) and the button ID (next-btn) based on your specific implementation.

That's it! With this solution, you should be able to achieve fade-in and fade-out animations on elements and set focus on a button based on specific Livewire variables.

UniTue's avatar

Cheers,

i wanted to give you an update:

The solution from Lary didn't worked out, i got the error that "afterDomUpdate" doen't exist.

Some more information: My first solution were CSS Animations and adding classes by javascript to the Elements that should fade in / fade out. This solution works out pretty well.

My second approach was adding the classes by livewire. I used something like:

<div id="type-div" class="
    @if(in_array($selectedType, [1,4,5])) 
				scale-in-center 
    @else 
				scale-out-center 
    @endif">

The third approach was to use AlpineJS (see my first post).

In this case I didn't get it up and running to set focus on my button, when an input was filled out correctly. I wanted to set the focus in javascript, but the element was still in animation while I tried to set the focus. So I used a little timeout (see first post) .. at that moment, I knew that this cannot be the solution.

Any help / hints / links appreciated.

Thank you

newbie360's avatar
// button component
@props(['label'])

@if ($attributes->has('transition'))
    <x-transition>
        <button {{ $attributes->except(['transition']) }}>
            {{ $label ?? $slot }}
        </button>
    </x-transition>
@else
    <button {{ $attributes }}>
        {{ $label ?? $slot }}
    </button>
@endif
// transition component
@props(['open']) {{-- No need this line, this is a php variable --}}

<div x-cloak
    x-show="open"
    x-transition:enter="transition ease-out duration-300"
    x-transition:enter-start="opacity-0 scale-90"
    x-transition:enter-end="opacity-100 scale-100"
    x-transition:leave="transition ease-in duration-300"
    x-transition:leave-start="opacity-100 scale-100"
    x-transition:leave-end="opacity-0 scale-90">
   {{ $slot }}
</div>

usage

<div x-data="{ open: @entangle('search').defer }">
    <x-elements.button 
        id="next-btn" 
        wire:click="searchLocation" 
        showIf="searchLocation" {{-- don't know what is this --}}
        autofocus
        label="next"
        transition {{-- optional --}}
    />
</div>

<div x-data="{ open: @entangle('search').defer }">
    <x-elements.button 
        id="next-btn" 
        wire:click="searchLocation" 
        showIf="searchLocation" {{-- don't know what is this --}}
        autofocus
    >
        <span class="text-lg">This button is without transition</span>
    </x-elements.button>
</div>

i think the above code is more readable

don't understand the question of the focus, it mean type something search it will lost focus on the input box? i think is a bad idea

UniTue's avatar

Hey Newbie360,

thank you for the code review.

The question of the focus was: I have a input field and an button. In the input field the user can search for items. When the user finds an item he can click on it. When the user clicks on the item, I want to fade in the "next step" button (using the transition) and set the focus to the button, so that the user can just press Enter to go on. I din't get it up and running until now. I use the timeout mentioned above, but I'm not happy with that solution.. it's not clean. Does somebody have a hint?

Cheers

Please or to participate in this conversation.