Documentation
Get alpine-js-swiper installed, then drive Swiper with Alpine expressions,
$swiper,
and event directives.
On this page
Install in two steps.
Requires Alpine.js 3. Swiper is bundled with the plugin, so you do not install it separately.
1. Add the package
npm install alpine-js-swiper
2. Register the plugin
Import the plugin and its stylesheet before calling
Alpine.start().
import Alpine from 'alpinejs';
import AlpineSwiper from 'alpine-js-swiper';
import 'alpine-js-swiper/style.css';
Alpine.plugin(AlpineSwiper);
Alpine.start();
Or drop it in with a CDN.
Load the stylesheet and alpine-js-swiper before Alpine.js. Both scripts may use
defer.
Pin the same release tag in production.
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/BillyNoyes/alpine-js-swiper@v1.1.1/dist/style.css">
<script defer src="https://cdn.jsdelivr.net/gh/BillyNoyes/alpine-js-swiper@v1.1.1/dist/alpine-js-swiper.min.js"></script>
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
<div x-data x-swiper="{ loop: true }" class="swiper">
<div class="swiper-wrapper">
<div class="swiper-slide">First</div>
<div class="swiper-slide">Second</div>
<div class="swiper-slide">Third</div>
</div>
<button type="button" @click="$swiper.slidePrev()">Previous</button>
<button type="button" @click="$swiper.slideNext()">Next</button>
</div>
Configure with Alpine expressions.
Pass any Swiper parameters to
x-swiper.
Options are evaluated when the directive initializes. For manual init, pass
init: false
and call
$swiper.init()
when ready.
<div
x-data="{
options: {
slidesPerView: 1,
spaceBetween: 24,
breakpoints: {
768: { slidesPerView: 2 },
1024: { slidesPerView: 3 }
}
}
}"
x-swiper="options"
class="swiper"
>
<div class="swiper-wrapper">
<div class="swiper-slide">One</div>
<div class="swiper-slide">Two</div>
<div class="swiper-slide">Three</div>
</div>
</div>
Call methods. Read reactive state.
$swiper
is available on the slider element and its descendants. Use
realIndex
for the visible slide when loop mode is on.
<div x-data x-swiper class="swiper">
<div class="swiper-wrapper">
<div class="swiper-slide">One</div>
<div class="swiper-slide">Two</div>
<div class="swiper-slide">Three</div>
</div>
<button type="button" @click="$swiper.slidePrev()" :disabled="$swiper.isBeginning">
Previous
</button>
<button type="button" @click="$swiper.slideNext()" :disabled="$swiper.isEnd">
Next
</button>
<span>
Slide <span x-text="$swiper.realIndex + 1"></span>
of <span x-text="$swiper.slides"></span>
</span>
</div>
- activeIndex: Swiper's internal index
- realIndex: content index without loop duplicates
- isBeginning / isEnd: edge state
- slides / progress: count and 0-1 progress
Bind Swiper events.
Prefix a kebab-case Swiper event with
x-swiper-event:.
Listeners are removed automatically when Alpine cleans up the element.
<div
x-data="{ message: 'Waiting…' }"
x-swiper
x-swiper-event:init="message = 'Ready'"
x-swiper-event:slide-change="message = `Showing slide ${$swiper.realIndex + 1}`"
class="swiper"
>
<div class="swiper-wrapper">
<div class="swiper-slide">One</div>
<div class="swiper-slide">Two</div>
</div>
<p x-text="message"></p>
</div>
Control sliders from outside.
Give a slider
data-swiper-id
when controls live outside its DOM subtree, then use
$store.swipers.
<div x-data>
<div data-swiper-id="gallery" x-swiper class="swiper">
<div class="swiper-wrapper">
<div class="swiper-slide">Front</div>
<div class="swiper-slide">Back</div>
</div>
</div>
<button type="button" @click="$store.swipers.getSwiper('gallery')?.slideTo(0)">
Show front image
</button>
</div>
Troubleshooting
Slides are stacked or unstyled
Import
alpine-js-swiper/style.css
or load
dist/style.css
from the CDN. The JavaScript bundle cannot apply Swiper’s stylesheet for you.
$swiper is undefined
Use it on the
x-swiper
element or a descendant. For sibling controls, set
data-swiper-id
and use
$store.swipers.
CDN build does not initialize
Keep script order as alpine-js-swiper first, Alpine.js second. Use matching branch, commit, or release tags for CSS and JS.
progress looks stuck in loop mode
$swiper.progress
mirrors Swiper’s translate progress. With
loop
and a fractional
slidesPerView,
that value may plateau below
1
while
realIndex
keeps cycling. Prefer
realIndex
for slide position UI.