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

Rretzko's avatar
Level 15

Toggle-able blade section flashes open when page opens, then closes

Hi Folks - I have a section at the top of my livewire 3 app pages (pageInstructions) that is open for the first-time user, but defaults to closed on subsequent visits by the user (via Alpine.js). This works as expected. However, the section flashes open and then closes whenever that page is opened or refreshed regardless of $firstTimer status. I've run the code through Lary and made the suggested changes, but the problem persists. I've also run view:clear and cache:clear to be sure. Your thoughts are appreciated! Livewire component

class BasePage extends Component
{
    public string $firstTimer = 'false';
}

calling blade section

<x-pageInstructions.instructions instructions="{!! $pageInstructions !!}" firstTimer="{{ $firstTimer }}"/>

pageInstructions.instructions

@props([
    'firstTimer' => 'false',
    'instructions',
])

    <div id="hideShowHeader" class="px-2" x-data="{ expanded:{{ $firstTimer === 'true' ? 'true' : 'false' }} }">
        <div class="flex flex-row justify-between">
            <div class="font-semibold">Page Instructions</div>
            <button type="button" x-on:click="expanded = ! expanded">
                <span x-show="! expanded" class="text-green-600 font-semibold">Show...</span>
                <span x-show="expanded" class="text-red-600">Hide...</span>
            </button>
        </div>

        <div id="instructions" class="p-8" x-show="expanded" x-transition.enter.duration.500ms
             x-transition:leave.duration.300ms>
            {!! $instructions !!}
        </div>

    </div>

</div>
0 likes
2 replies
LaryAI's avatar
Level 58

The issue you're experiencing is likely due to the way Alpine.js initializes the x-data attribute. When the page loads, Alpine.js evaluates the expanded property, which causes the section to momentarily flash open before closing if firstTimer is set to 'false'.

To prevent this flash, you can use the x-init directive to set the initial state of expanded after Alpine.js has initialized. This way, the section will not flash open and then close.

Here's how you can modify your pageInstructions.instructions Blade component to include x-init:

@props([
    'firstTimer' => 'false',
    'instructions',
])

@if($firstTimer === 'true') 
    <div>firstTimer = true</div> 
@endif

<div id="hideShowHeader" class="px-2" x-data="{ expanded: false }" x-init="expanded = {{ $firstTimer === 'true' ? 'true' : 'false' }}">
    <div class="flex flex-row justify-between">
        <div class="font-semibold">Page Instructions</div>
        <button type="button" x-on:click="expanded = ! expanded">
            <span x-show="! expanded" class="text-green-600 font-semibold">Show...</span>
            <span x-show="expanded" class="text-red-600">Hide...</span>
        </button>
    </div>

    <div id="instructions" class="p-8" x-show="expanded" x-transition:enter.duration.500ms x-transition:leave.duration.300ms>
        {!! $instructions !!}
    </div>
</div>

In this updated code, the x-data attribute initializes expanded to false, and then x-init sets expanded to the correct value based on the firstTimer property. This should prevent the flash of the section opening and then closing.

Additionally, ensure that your Livewire component correctly sets the $firstTimer property based on the user's visit status. If you need to persist this state across sessions, consider using a session variable or a database field to track whether the user is a first-time visitor.

Rretzko's avatar
Level 15

Hi - I made the additional changes suggested in the x-init (with some editing suggested by phpstorm) and x-data commands but the problem persists.

<div class="w-full px-1 py-2 mx-2 my-1 bg-gray-100 rounded-lg">

    <div id="hideShowHeader" class="px-2" x-data="{ expanded: false }" x-init="expanded = {{ $firstTimer === 'true'  }}">
        <div class="flex flex-row justify-between">
            <div class="font-semibold">Page Instructions</div>
            <button type="button" x-on:click="expanded = ! expanded">
                <span x-show="! expanded" class="text-green-600 font-semibold">Show...</span>
                <span x-show="expanded" class="text-red-600">Hide...</span>
            </button>
        </div>
...

Please or to participate in this conversation.