rupadana/filament-swiper
A Filament plugin that brings Swiper.js sliders and carousels to your admin panel, with ready-made form and blade components for building responsive image or content sliders without writing JavaScript yourself.
rupadana/filament-swiper is a Filament plugin that wraps Swiper.js as a form component, so you can drop a touch-friendly, responsive slide/carousel field into a Filament resource form instead of hand-rolling Alpine + Swiper markup.
Minimal steps:
composer require rupadana/filament-swiper:^3.0
Note the package is still beta (3.0.5-beta); pin to ^3.0@beta explicitly, or use 3.0.*@beta.->plugin(FilamentSwiperPlugin::make())
If your installed version exposes only the field, skip this and just use the component.php artisan vendor:publish --tag="filament-swiper-config" / --tag="filament-swiper-assets") and confirm Swiper CSS/JS is loaded — the component is useless without the bundled assets.PostForm or a settings page, e.g. a Swiper/SwiperInput field bound to a json or array cast column holding image paths + captions, then render the same data on the front end with your own Swiper instance (or the package's Blade view, if provided).Where to look first: the package's README, config/filament-swiper.php, the src/ field class (to see the public fluent API: disk(), directory(), imageSize(), etc. — names vary by version), and the published Blade view to understand the DOM contract. Since there is no documentation site, the source is the documentation.
Treat the field as a structured repeater, not a single upload. The usual workflow is: one column (json) storing an ordered array of { image, alt, caption, link } objects; the Filament field handles upload + reorder; a Spatie\MediaLibrary or plain FileUpload-style disk config in the field controls storage. Cast in the model:
protected function casts(): array {
return ['slides' => 'array'];
}
Pair it with ->columnSpanFull() inside a Section — carousels need horizontal room and look cramped in a 1/2-column grid.
Keep the admin preview shallow. Render only the first 1–3 slides in the form (slidesPerView, loop(false)) so the panel stays fast on records with 20+ images. Save full-fidelity data; preview cheaply.
Front-end rendering is yours. The plugin's job ends at storing structured data. A common pattern is a Blade partial + a small @vite-loaded JS module that instantiates Swiper on [data-swiper] elements, driven by the JSON column. This decouples you from the package's beta front-end and means an upgrade can't break your public site.
Multi-panel / multi-form reuse: extract the field definition into a static method on the form schema class so the same slider configuration is shared between the resource form and a settings page, rather than duplicating fluent chains.
Testing: Livewire/Filament tests should assert the stored JSON shape (assertDatabaseHas with a JSON fragment) rather than any Swiper DOM. Any assertion on .swiper-wrapper in a Pest test is a maintenance trap.
3.0.x-beta releases have shipped breaking-ish changes (asset handling, Filament v4/v5 alignment). Pin the exact version in composer.json for production panels and upgrade deliberately; do not float on ^3.0 with minimum-stability: dev.3.0.4-beta tags will trip composer conflict rules against laravel/framework:^12.0.Filament\Forms\Components namespaces and different asset registration APIs). Check composer.json require in the package before debugging anything else.->live(), ->reactive(), wizard steps) will leave a dead carousel. Fix by scoping an initSwiper() call in an x-init/Livewire.hook('morph.updated') listener and destroying the previous instance (swiper.destroy(true, true)), or by keying the container so Livewire replaces it wholesale.ids/selectors. If the component generates a fixed class, wrap it and instantiate per-element (.swiper → querySelectorAll) rather than querySelector.php artisan filament:assets (or your vendor:publish --force) as part of the deploy script, and confirm the Swiper bundle is in public/. A carousel that renders as a vertical stack of images is almost always missing CSS.disk() differs from your FILESYSTEM_DISK, Storage::url() paths will break on the front end. Store relative paths, resolve URLs at render time, and be explicit about visibility('public') for S3-compatible disks.width/height or an aspect-ratio container in your Blade view; Swiper's default layout will otherwise jump on load and drag your Lighthouse score down.a11y and provide navigation/pagination with real labels. Budget for this — it is not a config flag in the package.resources/views/vendor/filament-swiper/ rather than subclassing the field, and note the view name in your upgrade checklist since it is the most likely thing to change between betas.php artisan about for the Filament version, then ddup the component's getViewData() — nine times out of ten it is a namespace/version mismatch or an unregistered asset, not your data.How can I help you explore Laravel packages today?