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

Rretzko's avatar
Level 15

Livewire/Apine popover button locked in open position and unresponsive to clicks.

I'm using Livewire and Alpine to set filters for a table. I've used the 'popover' coding demo'd by Caleb on the screencasts but the popover panel is frozen in the open position and the button does not respond to clicks, nor does the panel close when clicking outside of the panel. All help is appreciated!

schools.blade.php

<x-popover>
    <div class="flex flex-row">
        <x-popover.button buttonId="filter-schools" class="flex items-center gap-2 rounded-lg border pl-3 pr-2 py-1 text-gray-600 text-sm">
            <div>Filter</div>
            <x-heroicons.chevronDown/>
        </x-popover.button>
    </div>

    <x-popover.panel buttonId="filter-schools" class="border border-gray-100 shadow-xl z-10 w-64 overflow-hidden">
        <div class="flex flex-col divide-y divide-gray-100">
            @foreach ($filters->schools() as $school)
                <label class="flex items-center px-3 py-2 gap-2 cursor-pointer hover:bg-gray-100">
                    <input value="{{ $school->id }}" wire:model.live="filters.selectedSchoolIds" type="checkbox" class="rounded border-gray-300">

                    <div class="text-sm text-gray-800">{{ $school->name }}</div>
                </label>
            @endforeach
        </div>
    </x-popover.panel>
</x-popover>

popover.button.blade.php

@props(['buttonId'])
<button id="{{ $buttonId }}" type="button" x-popover:button {{ $attributes }}>
    {{ $slot }}
</button>

popover.panel.blade.php

@props(['position' => 'bottom-center', 'buttonId'])

<div
    x-popover:panel
    x-cloak
    x-transition.out.opacity
    x-anchor.{{ $position }}.offset.1="document.getElementById('{{ $buttonId }}')"
    {{ $attributes->merge([
        'class' => 'absolute left-0 mt-2 bg-white rounded-md',
    ]) }}
>
    {{ $slot }}
</div>
0 likes
1 reply
LaryAI's avatar
Level 58

It looks like you're using Livewire and Alpine.js to create a popover component, but the popover is stuck in the open position and unresponsive to clicks. This issue is often related to the Alpine.js directives not being properly initialized or conflicts with Livewire's reactivity.

Here are a few steps to troubleshoot and resolve the issue:

  1. Ensure Alpine.js is properly included and initialized: Make sure you have included Alpine.js in your project and that it is initialized correctly. You can include Alpine.js in your app.blade.php or main layout file:

    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/cdn.min.js" defer></script>
    
  2. Check for Alpine.js and Livewire compatibility: Ensure that you are using compatible versions of Alpine.js and Livewire. Sometimes, newer versions of one library may introduce breaking changes that affect the other.

  3. Initialize Alpine.js after Livewire updates: Livewire can sometimes interfere with Alpine.js components. To ensure Alpine.js components are re-initialized after Livewire updates, you can use the livewire:load and livewire:update events:

    <script>
        document.addEventListener('livewire:load', () => {
            Alpine.start();
        });
    
        document.addEventListener('livewire:update', () => {
            Alpine.start();
        });
    </script>
    
  4. Ensure proper use of Alpine.js directives: Verify that the Alpine.js directives are correctly applied in your popover.button.blade.php and popover.panel.blade.php files. Here is a revised version of your components:

    popover.button.blade.php:

    @props(['buttonId'])
    
    <button id="{{ $buttonId }}" type="button" x-data x-on:click="$dispatch('toggle', { id: '{{ $buttonId }}' })" {{ $attributes }}>
        {{ $slot }}
    </button>
    

    popover.panel.blade.php:

    @props(['position' => 'bottom-center', 'buttonId'])
    
    <div
        x-data="{ open: false }"
        x-show="open"
        x-cloak
        x-transition.out.opacity
        x-on:toggle.window="if ($event.detail.id === '{{ $buttonId }}') open = !open"
        x-on:click.away="open = false"
        x-anchor.{{ $position }}.offset.1="document.getElementById('{{ $buttonId }}')"
        {{ $attributes->merge([
            'class' => 'absolute left-0 mt-2 bg-white rounded-md',
        ]) }}
    >
        {{ $slot }}
    </div>
    
  5. Ensure Livewire reactivity: Make sure that your Livewire component is correctly handling the reactivity for the filters. If you are using wire:model.live, ensure that the Livewire component is properly set up to handle the updates.

By following these steps, you should be able to resolve the issue with the popover being stuck in the open position and unresponsive to clicks. If the problem persists, consider checking the browser console for any JavaScript errors that might provide more insight into the issue.

Please or to participate in this conversation.