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

willstori's avatar

Update carousel with Liverwire 3 + Swiper.js

how are you?

I'm having an issue with updating the slides of my carousel controlled by Livewire. Every time I filter the slides with Livewire, the carousel breaks. Below is the code for my component.

Blade file of the component:

<div class="container">
    <div class="d-flex gap-2 justify-content-center py-5">
        <button
            class="btn {{ $type == 'type 1' ? 'btn-primary' : 'btn-outline-primary' }} d-inline-flex align-items-center"
            type="button" wire:click="filterBanners('type 1')">
            Type 1
        </button>
        <button
            class="btn {{ $type == 'type 2' ? 'btn-primary' : 'btn-outline-primary' }} d-inline-flex align-items-center"
            type="button" wire:click="filterBanners('type 2')">
            Type 2
        </button>
    </div>

    <div class="swiper-container">
        <div class="swiper-wrapper">
            @foreach ($banners as $banner)
                <div class="swiper-slide" wire:key="banner-{{ $banner->id }}">
                    <img class="w-100" src="{{ $banner->url }}" alt="{{ $banner->name }}">
                </div>
            @endforeach
        </div>
        <div class="swiper-pagination"></div>
    </div>
</div>

@assets
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/Swiper/4.4.6/css/swiper.css">
    <script src="https://cdnjs.cloudflare.com/ajax/libs/Swiper/4.4.6/js/swiper.min.js"></script>
@endassets

@script
    <script>
        window.swiper = new Swiper('.swiper-container', {
            slidesPerView: 3,
            spaceBetween: 90,
            autoplay: {
                delay: 6000,
                disableOnInteraction: false,
            },
            pagination: {
                el: '.swiper-container .swiper-pagination',
                clickable: true,
            },
            breakpoints: {
                1400: {
                    spaceBetween: 40,
                },
                900: {
                    slidesPerView: 2,
                    spaceBetween: 30,
                },
                550: {
                    slidesPerView: 1,
                    spaceBetween: 30,
                }
            }
        });

        /* Event */
        $wire.on('refresh-banners', () => {
            window.swiper.update();
        });
    </script>
@endscript

PHP code of the component:

namespace App\Livewire;

use App\Models\Banner;
use Livewire\Component;

class ListBanner extends Component
{
    public $type = '';

    public $banners;

    public function mount()
    {
        $this->type = 'type 1';

        $this->banners = Banner::where('banners.type', $this->type)->get();
    }

    public function filterBanners($type)
    {
        $this->type = $type;

        $this->banners = Banner::where('banners.type', $this->type)->get();

        $this->dispatch('refresh-banners');
    }

    public function render()
    {
        return view('livewire.list-banner');
    }
}

I believe what's happening is that the window.swiper.update(); function is being executed before the elements are fully loaded, causing the bug in the carousel display.

I even managed to achieve a satisfactory result by replacing the 'refresh-banners' event with the hook:

Livewire.hook('morph.updated', ({ el, component }) => {
   window.swiper.update();
});

But this results in multiple unnecessary calls to the update method.

I need the carousel to be updated with the new slides when clicking on the filter buttons.

1 like
1 reply

Please or to participate in this conversation.