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

nscott's avatar

Lightbox with captions pulling the same caption

My captions do not seem to be getting pulled in properly on my lightbox. If I click on any image initially to open the lightbox, they all start with the first caption. The same thing happens when I click on the back or next buttons, it is always the same caption. If the lightbox is open and I click on one of the image thumbs, then the proper caption comes up, but then I click back or forward and it goes right back to the first caption. If I exit out of the light box and click another image, it loads the caption from the thumb I clicked inside the light box. Here is the component:

<div x-data="{ isOpen: false, currentImage: 0, images: [
    @foreach($images as $key => $image)
        { small: '{{ asset($image['small']) }}', large: '{{ asset($image['large']) }}', caption: '{{ $image['caption'] }}' },
        @unless($loop->last)@endunless
    @endforeach
] }">
    <div class="lightbox-grid">
        @foreach($images as $key => $image)
            <div class="lightbox-thumbnail" @click="isOpen = true; currentImage = {{ $key }}">
                <img :src="images[{{ $key }}].small" alt="Thumbnail {{ $key }}">
            </div>
        @endforeach
    </div>

    <div x-show="isOpen" class="lightbox-overlay">
        <div class="lightbox-content" x-data="{ currentCaption: '{{ $images[0]['caption'] }}' }">
            <img :src="images[currentImage].large" alt="Large Image">
            <div class="lightbox-caption" x-text="currentCaption"></div>
            <div class="lightbox-thumbnails">
                @foreach($images as $key => $image)
                    <div class="lightbox-thumbnail" @click="currentImage = {{ $key }}; currentCaption = '{{ $image['caption'] }}'">
                        <img :src="images[{{ $key }}].small" alt="Thumbnail {{ $key }}">
                    </div>
                @endforeach
            </div>
            <button @click="isOpen = false" class="lightbox-close">&#10005;</button>
            <button @click="currentImage = (currentImage - 1 + images.length) % images.length; currentCaption = '{{ $images[0]['caption'] }}'" class="lightbox-prev">&lt;</button>
            <button @click="currentImage = (currentImage + 1) % images.length; currentCaption = '{{ $images[0]['caption'] }}'" class="lightbox-next">&gt;</button>
        </div>
    </div>
</div>

Here is my sample data:

public function render()
    {
        $images = [

            ['small' => asset('img/gallery/staypanel_forms_installation_laguardia_project_gallery_small_01.webp'), 'large' => asset('img/gallery/staypanel_forms_installation_laguardia_project_gallery_large_01.webp'), 'caption' => 'Image 1'],
            ['small' => asset('img/gallery/staypanel_forms_installation_laguardia_project_gallery_small_02.webp'), 'large' => asset('img/gallery/staypanel_forms_installation_laguardia_project_gallery_large_02.webp'), 'caption' => 'Image 2'],
            ['small' => asset('img/gallery/staypanel_forms_installation_laguardia_project_gallery_small_03.webp'), 'large' => asset('img/gallery/staypanel_forms_installation_laguardia_project_gallery_large_03.webp'), 'caption' => 'Image 3'],
            ['small' => asset('img/gallery/staypanel_forms_installation_laguardia_project_gallery_small_04.webp'), 'large' => asset('img/gallery/staypanel_forms_installation_laguardia_project_gallery_large_04.webp'), 'caption' => 'Image 4'],
            ['small' => asset('img/gallery/staypanel_forms_installation_laguardia_project_gallery_small_05.webp'), 'large' => asset('img/gallery/staypanel_forms_installation_laguardia_project_gallery_large_05.webp'), 'caption' => 'Image 5'],
            ['small' => asset('img/gallery/staypanel_forms_installation_laguardia_project_gallery_small_06.webp'), 'large' => asset('img/gallery/staypanel_forms_installation_laguardia_project_gallery_large_06.webp'), 'caption' => 'Image 6'],
            ['small' => asset('img/gallery/staypanel_forms_installation_laguardia_project_gallery_small_07.webp'), 'large' => asset('img/gallery/staypanel_forms_installation_laguardia_project_gallery_large_07.webp'), 'caption' => 'Image 7'],
            ['small' => asset('img/gallery/staypanel_forms_installation_laguardia_project_gallery_small_08.webp'), 'large' => asset('img/gallery/staypanel_forms_installation_laguardia_project_gallery_large_08.webp'), 'caption' => 'Image 8'],
        ];

        return view('components.lightbox', compact('images'));
    }

I am not sure where I screwed this all up. This both a Laravel and AlpineJs question.

0 likes
2 replies
LaryAI's avatar
Level 58

It looks like the issue is with how the caption is being updated when navigating through the images. The currentCaption is being set to the caption of the first image every time you navigate to the previous or next image. Instead, you should update the currentCaption to the caption of the current image after navigating.

Here's the corrected code for the navigation buttons:

<button @click="currentImage = (currentImage - 1 + images.length) % images.length; currentCaption = images[currentImage].caption" class="lightbox-prev">&lt;&lt;</button>
<button @click="currentImage = (currentImage + 1) % images.length; currentCaption = images[currentImage].caption" class="lightbox-next">&gt;&gt;</button>

However, there's a catch: because the currentImage is updated before currentCaption, you might encounter a race condition where the caption does not update correctly. To fix this, you can use Alpine.js's $nextTick to ensure that the caption is updated after the currentImage has been updated:

<button @click="currentImage = (currentImage - 1 + images.length) % images.length; $nextTick(() => { currentCaption = images[currentImage].caption })" class="lightbox-prev">&lt;&lt;</button>
<button @click="currentImage = (currentImage + 1) % images.length; $nextTick(() => { currentCaption = images[currentImage].caption })" class="lightbox-next">&gt;&gt;</button>

Make sure to apply this change to both the previous and next buttons. This should ensure that the correct caption is displayed when navigating through the images in the lightbox.

nscott's avatar

@LaryAI That does help with the next and previous buttons. However, the first caption still comes up whenever I click any image to open up the lightbox. And once I click through to another image, that caption is the one the sticks once you close the lightbox and click an image.

Please or to participate in this conversation.