Skip to content

Carousels · Open source

Laravel Swiper

Swiper sliders, carousels and image galleries for Laravel as Blade components.

Laravel 12 and 13 PHP 8.3+ v1.0.1 Free · MIT
Laravel Swiper: Swiper sliders, carousels and image galleries for Laravel as Blade components.

What it solves

Dropping Swiper into a Laravel app is quick, but a Livewire update morphs its markup back to the server HTML: arrows double up, the slide jumps back to the start, and after wire:navigate it never starts.

The images also come from storage or models, not a hard-coded array, and carousel accessibility is easy to get wrong.

Navigation, pagination, thumbs, autoplay and effects are typed props on <x-swiper>. Slides come from your own markup, a collection of models or Spatie Media items, or a folder on a storage disk, and a carousel is rebuilt only when its content changed, on the same slide.

  • Typed, validated props for navigation, pagination, thumbs, autoplay, effects and breakpoints
  • Unchanged carousels survive Livewire updates; changed ones are rebuilt on the same slide
  • Starts again after wire:navigate, with no duplicate scripts
  • Image slides from paths, URLs, Eloquent models, Spatie Media items or a storage disk folder, private disks included
  • Lazy images with a fixed aspect ratio, a high-priority first image, and srcset from your image resizer
  • Labelled carousel region, button arrows, a pause button for autoplay, and prefers-reduced-motion support
An image carousel titled Folder on the public disk, with thumbs: a large blue slide labelled 1, lake at dawn, with previous and next arrows and pagination bullets, above a strip of six thumbnails with the first one highlighted.
An image carousel titled Folder on the public disk, with thumbs: a large blue slide labelled 1, lake at dawn, with previous and next arrows and pagination bullets, above a strip of six thumbnails with the first one highlighted.

Install

Requires PHP 8.3+ and Laravel 12 and 13.

composer require amjadiqbal/laravel-swiper

Usage

{{-- Every image in storage/app/public/gallery, with a thumbnail strip --}}
<x-swiper folder="gallery" disk="public" thumbs />

{{-- Any markup you like --}}
<x-swiper loop :autoplay="5000" label="Customer stories">
    @foreach ($stories as $story)
        <x-swiper.slide><x-story-card :story="$story" /></x-swiper.slide>
    @endforeach
</x-swiper>

Setup

The first <x-swiper> on a page prints Swiper 14.3.0 from jsDelivr, with Subresource Integrity hashes, and a small runtime. With Livewire, also put @swiperAssets in your layout's <head>.

<head>
    ...
    @swiperAssets
</head>

Slides and image carousels

:images takes paths, URLs, arrays, objects, Eloquent models or Spatie Media items. Without image-field it tries image, src, url, path, photo and cover; each *-field accepts dot notation or a closure. folder lists every image file directly in that folder, in natural order, and builds alt text from the file name. Paths are turned into URLs with the disk's url(). For a private disk or bucket, set swiper.images.temporary_urls to a number of minutes (for every disk, or per disk) and they use temporaryUrl() instead. Slide links from link-field only allow http(s), mailto, tel and relative URLs, so a javascript: URL in your data is dropped.

<x-swiper :images="$products"
          image-field="cover.path"
          :alt-field="fn ($p) => $p->name.' in '.$p->colour"
          caption-field="tagline"
          link-field="url" />

<x-swiper :images="$post->getMedia('gallery')" conversion="large" thumbs />

Responsive images

Laravel stores one file per image, so srcset needs an image CDN or resizer. Set srcset_url in config/swiper.php, or build the URLs with Swiper::srcsetUsing(). Spatie Media items use their own srcset. sizes is worked out from slides-per-view and breakpoints; [768 => 2] gives (min-width: 768px) 50vw, 100vw. SVGs never get a srcset.

// config/swiper.php
'images' => [
    'srcset_url' => '{url}?w={width}&fm=webp',
    'widths' => [480, 800, 1200, 1600, 2000],
],

Livewire and wire:navigate

Nothing to set up. A carousel stays as it is when an update does not change it, is rebuilt on the same slide when its slides or options change, and starts again after wire:navigate. If the visitor paused autoplay, it stays paused. swiper:init and swiper:slide-change events bubble from the carousel.

$this->dispatch('swiper:go', id: 'gallery', index: 2);   // Livewire

<button @click="$dispatch('swiper:go', { id: 'gallery', index: 0 })">Back to start</button>   {{-- Alpine --}}

Accessibility and assets

  • Each carousel is a region with your label (Carousel by default) and an aria-roledescription of carousel; each slide is labelled such as 2 of 5.
  • Arrows are <button> elements with labels, and pagination bullets are labelled Go to slide 3.
  • Autoplay adds a pause/play button and pauses while keyboard focus is inside or the mouse is over the carousel.
  • With prefers-reduced-motion: reduce there is no autoplay and slides change instantly (swiper.reduced_motion turns this off).
  • Arrow keys, Home and End move only the carousel in use.
  • SWIPER_ASSETS is cdn (the default), local (publish with --tag=swiper-assets) or none (you load Swiper with Vite). Messages are published with --tag=swiper-translations and the config with --tag=swiper-config.

Hire me

Need this built into your app, or something custom?

I wrote Laravel Swiper. I can wire it into your Laravel app, extend it for your case, or build the feature around it. Tell me what you need and you'll get a plan and a quote, free.

Support

Found a bug or want a feature? Open an issue on GitHub. For help adding it to your own project, use the quote form above.

Need something built?

Free quote in 60 seconds