Swiper web components are available since Swiper version 9.
Custom elements are supported in all major browsers and by almost every framework.
There are few options on how to install Swiper Element into your project:
We can install Swiper from NPM
$ npm install swiper
When you import Swiper custom elements from node modules, we need to manually register it. It should be done only once and it registers Swiper custom elements globally.
// import function to register Swiper custom elements
import { register } from 'swiper/element/bundle';
// register Swiper custom elements
register();
You can also install it from CDN by directly adding it to the website with <script>
tag:
<script src="https://cdn.jsdelivr.net/npm/swiper@11/swiper-element-bundle.min.js"></script>
In this case, it will be automatically registered, no need to call register()
After we install Swiper Element (via node modules and calling register()
or by including a script tag), there are 2 web components (custom elements) available for usage:
<swiper-container>
- main Swiper element where you define all parameters<swiper-slide>
- Swiper slide element<swiper-container>
<swiper-slide>Slide 1</swiper-slide>
<swiper-slide>Slide 2</swiper-slide>
<swiper-slide>Slide 3</swiper-slide>
...
</swiper-container>
All Swiper parameters are available in a form of kebab-case
attributes on <swiper-container>
, for example:
<swiper-container slides-per-view="3" speed="500" loop="true" css-mode="true">
<swiper-slide>Slide 1</swiper-slide>
<swiper-slide>Slide 2</swiper-slide>
<swiper-slide>Slide 3</swiper-slide>
...
</swiper-container>
All parameters that are passed as objects also can be passed as attributes in a form of [key]-[subkey]="value"
.
For example, such configuration:
new Swiper('.swiper', {
slidesPerView: 3,
grid: {
rows: 3,
},
mousewheel: {
forceToAxis: true,
},
});
should be passed in this way:
<swiper-container
slides-per-view="3"
grid-rows="3"
mousewheel-force-to-axis="true"
>
<swiper-slide>Slide 1</swiper-slide>
<swiper-slide>Slide 2</swiper-slide>
<swiper-slide>Slide 3</swiper-slide>
...
</swiper-container>
In some more complex cases when we have more complex parameters objects (like with breakpoints), we can pass all parameters as HTMLElement
properties.
Here, we need to add init="false"
attribute to prevent Swiper from initialization until we pass all required parameters.
<!-- Add init="false" -->
<swiper-container init="false">
<swiper-slide>Slide 1</swiper-slide>
<swiper-slide>Slide 2</swiper-slide>
<swiper-slide>Slide 3</swiper-slide>
...
</swiper-container>
<script>
// swiper element
const swiperEl = document.querySelector('swiper-container');
// swiper parameters
const swiperParams = {
slidesPerView: 1,
breakpoints: {
640: {
slidesPerView: 2,
},
1024: {
slidesPerView: 3,
},
},
on: {
init() {
// ...
},
},
};
// now we need to assign all parameters to Swiper element
Object.assign(swiperEl, swiperParams);
// and now initialize it
swiperEl.initialize();
</script>
Swiper parameters can be updated by directly changing Swiper element attributes or HTMLElement
properties (if it was initialized with props);
<swiper-container slides-per-view="1">
<swiper-slide>Slide 1</swiper-slide>
<swiper-slide>Slide 2</swiper-slide>
<swiper-slide>Slide 3</swiper-slide>
...
</swiper-container>
<button>Update</button>
<script>
const swiperEl = document.querySelector('swiper-container');
const buttonEl = document.querySelector('button');
buttonEl.addEventListener('click', () => {
// if it was initialized with attributes
swiperEl.setAttribute('slides-per-view', '3');
// or if it was initialized with props
swiperEl.slidesPerView = 3;
});
</script>
Initialized Swiper instance is available as swiper
prop of Swiper's HTMLElement
:
<swiper-container slides-per-view="1">
<swiper-slide>Slide 1</swiper-slide>
<swiper-slide>Slide 2</swiper-slide>
<swiper-slide>Slide 3</swiper-slide>
...
</swiper-container>
<button>Slide Next</button>
<script>
const swiperEl = document.querySelector('swiper-container');
const buttonEl = document.querySelector('button');
buttonEl.addEventListener('click', () => {
swiperEl.swiper.slideNext();
});
</script>
All Swiper events are available as native DOM events but with lowercase names and swiper
prefix (configurable via events-prefix
parameter). E.g. slideChange
becomes swiperslidechange
.
All event handler arguments are passed as array in event.detail
:
<swiper-container>
<swiper-slide>Slide 1</swiper-slide>
<swiper-slide>Slide 2</swiper-slide>
<swiper-slide>Slide 3</swiper-slide>
...
</swiper-container>
<script>
const swiperEl = document.querySelector('swiper-container');
swiperEl.addEventListener('swiperprogress', (event) => {
const [swiper, progress] = event.detail;
});
swiperEl.addEventListener('swiperslidechange', (event) => {
console.log('slide changed');
});
</script>
It is also possible to prefix emitted events names to prevent clashing with other libs or native events using events-prefix
attribute/parameter:
<swiper-container events-prefix="swiper-">
<swiper-slide>Slide 1</swiper-slide>
<swiper-slide>Slide 2</swiper-slide>
<swiper-slide>Slide 3</swiper-slide>
...
</swiper-container>
<script>
const swiperEl = document.querySelector('swiper-container');
swiperEl.addEventListener('swiper-progress', (event) => {
const [swiper, progress] = event.detail;
});
swiperEl.addEventListener('swiper-slidechange', (event) => {
console.log('slide changed');
});
</script>
If you don't pass these modules elements in parameters (e.g. scrollbar.el
, pagination.el
), it will render them automatically, if module parameter is specified:
<!-- enable navigation, pagination, scrollbar -->
<swiper-container navigation="true" pagination="true" scrollbar="true">
<swiper-slide>Slide 1</swiper-slide>
<swiper-slide>Slide 2</swiper-slide>
<swiper-slide>Slide 3</swiper-slide>
...
</swiper-container>
If you use lazy loading images, it requires the lazy preloader element to be added to the each slide. swiper-slide
component can do this automatically by adding lazy="true"
attribute:
<swiper-container>
<!-- lazy="true" attribute will automatically render the preloader element -->
<swiper-slide lazy="true">
<img src="..." loading="lazy" />
</swiper-slide>
<swiper-slide lazy="true">
<img src="..." loading="lazy" />
</swiper-slide>
<swiper-slide lazy="true">
<img src="..." loading="lazy" />
</swiper-slide>
...
</swiper-container>
We have 2 options to use Virtual slides in Swiper web components.
First option is to pass slides in virtual.slides
array, but it will require to use element properties to initialize Swiper element:
<swiper-container init="false"></swiper-container>
<script>
// swiper element
const swiperEl = document.querySelector('swiper-container');
// swiper parameters
const swiperParams = {
virtual: {
// virtual slides
slides: ['Slide 1', 'Slide 2', 'Slide 3'],
},
};
// assign all parameters to Swiper element
Object.assign(swiperEl, swiperParams);
// and now initialize it
swiperEl.initialize();
</script>
Since version 9, Swiper virtual slides can work with slides originally rendered in DOM. On initialize it will remove them from DOM, cache and then re-use the ones which are required:
<!-- it is enough to add virtual="true" attribute -->
<swiper-container virtual="true">
<swiper-slide>Slide 1</swiper-slide>
<swiper-slide>Slide 2</swiper-slide>
<swiper-slide>Slide 3</swiper-slide>
...
</swiper-container>
In version 9 thumbs.swiper
parameter also accepts CSS Selector of the thumbs swiper. So to make both with Swiper elements we can use the following:
<!-- main swiper, pass thumbs swiper as CSS selector -->
<swiper-container thumbs-swiper=".my-thumbs"> ... </swiper-container>
<!-- thumbs swiper -->
<swiper-container class="my-thumbs"> ... </swiper-container>
Same as with Thumbs, Controller in version 9 also accepts CSS Selector:
<swiper-container class="swiper-1" controller-control=".swiper-2">
...
</swiper-container>
<swiper-container class="swiper-2" controller-control=".swiper-1">
...
</swiper-container>
If you need to add styles to shadow DOM scope, you can use injectStyles
or injectStylesUrls
parameters, e.g.:
<swiper-container init="false"> ... </swiper-container>
<script type="module">
import { register } from 'swiper/element/bundle';
register();
const swiperEl = document.querySelector('swiper-container');
const params = {
// array with CSS styles
injectStyles: [
`
:host(.red) .swiper-wrapper {
background-color: red;
}
`,
],
// array with CSS urls
injectStylesUrls: ['path/to/one.css', 'path/to/two.css'],
};
Object.assign(swiperEl, params);
swiperEl.initialize();
</script>
There is also Core version of Swiper element available (without additional modules).
It can be imported from node modules:
// import function to register Swiper Core custom elements
import { register } from 'swiper/element';
// register Swiper custom elements
register();
To add modules, we need to use modules
parameter as usual to include modules scripts, and we also need to add modules styles globally and also inject modules styles to the shadow DOM
<swiper-container init="false"> ... </swiper-container>
<script>
import { register } from 'swiper/element';
import { Navigation, Pagination } from 'swiper/modules';
register();
const swiperEl = document.querySelector('swiper-container');
const params = {
modules: [Navigation, Pagination],
// inject modules styles to shadow DOM
injectStylesUrls: [
'path/to/navigation-element.min.css',
'path/to/pagination-element.min.css',
],
};
Object.assign(swiperEl, params);
swiperEl.initialize();
</script>
There are following element module styles imports available:
swiper/element/css/a11y
- styles required for A11y moduleswiper/element/css/autoplay
- styles required for Autoplay moduleswiper/element/css/controller
- styles required for Controller moduleswiper/element/css/effect-cards
- styles required for Cards Effect moduleswiper/element/css/effect-coverflow
- styles required for Coverflow Effect moduleswiper/element/css/effect-creative
- styles required for Creative Effect moduleswiper/element/css/effect-cube
- styles required for Cube Effect moduleswiper/element/css/effect-fade
- styles required for Fade Effect moduleswiper/element/css/effect-flip
- styles required for Flip Effect moduleswiper/element/css/free-mode
- styles required for Free Mode moduleswiper/element/css/grid
- styles required for Grid moduleswiper/element/css/hash-navigation
- styles required for Hash Navigation moduleswiper/element/css/history
- styles required for History moduleswiper/element/css/keyboard
- styles required for Keyboard moduleswiper/element/css/manipulation
- styles required for Manipulation moduleswiper/element/css/mousewheel
- styles required for Mousewheel moduleswiper/element/css/navigation
- styles required for Navigation moduleswiper/element/css/pagination
- styles required for Pagination moduleswiper/element/css/parallax
- styles required for Parallax moduleswiper/element/css/scrollbar
- styles required for Scrollbar moduleswiper/element/css/thumbs
- styles required for Thumbs moduleswiper/element/css/virtual
- styles required for Virtual moduleswiper/element/css/zoom
- styles required for Zoom moduleBy default all swiper-container
children are rendered as children of .swiper-wrapper
element. If you need to add elements before or after there are two slots available:
container-start
- will be rendered before .swiper-wrapper
container-end
- will be rendered after .swiper-wrapper
<swiper-container>
<div slot="container-start">Rendered before wrapper</div>
<div slot="container-end">Rendered after wrapper</div>
<swiper-slide>Slide 1</swiper-slide>
<swiper-slide>Slide 2</swiper-slide>
<swiper-slide>Slide 3</swiper-slide>
...
</swiper-container>
There are following CSS parts are available for styling:
container
- styles for <div class="swiper">
wrapper
- styles for <div class="swiper-wrapper">
button-prev
- styles for prev Navigation button <div class="swiper-button-prev">
button-next
- styles for next Navigation button <div class="swiper-button-next">
pagination
- styles for prev Pagination container <div class="swiper-pagination">
bullet
- styles for Pagination bullet elementbullet-active
- styles for active Pagination bullet elementscrollbar
- - styles for Scrollbar container <div class="swiper-scrollbar">
For example:
swiper-container::part(bullet-active) {
background-color: red;
}
Since 9.1.0 there is a new global window.SwiperElementRegisterParams
function to register new (or extra) params that are not part of default Swiper parameters. This may be required if you use Swiper element with some custom plugins which extend Swiper parameters.
// register swiper-container HTMLElement props to be treated as Swiper parameters
window.SwiperElementRegisterParams(['foo', 'bar']);
const swiperEl = document.querySelector('swiper-container');
Object.assign(swiperEl, {
foo: 1,
bar: 2,
});
swiperEl.initialize();
React doesn't fully supports web components yet (as for version 18). So the usage is basically the same as in HTML:
import { useRef, useEffect } from 'react';
import { register } from 'swiper/element/bundle';
register();
export const MyComponent = () => {
const swiperElRef = useRef(null);
useEffect(() => {
// listen for Swiper events using addEventListener
swiperElRef.current.addEventListener('swiperprogress', (e) => {
const [swiper, progress] = e.detail;
console.log(progress);
});
swiperElRef.current.addEventListener('swiperslidechange', (e) => {
console.log('slide changed');
});
}, []);
return (
<swiper-container
ref={swiperElRef}
slides-per-view="3"
navigation="true"
pagination="true"
>
<swiper-slide>Slide 1</swiper-slide>
<swiper-slide>Slide 2</swiper-slide>
<swiper-slide>Slide 3</swiper-slide>
...
</swiper-container>
);
};
Vue has full support for web components, including passing attributes as props and listening for custom events:
<template>
<swiper-container
:slides-per-view="3"
:space-between="spaceBetween"
:centered-slides="true"
:pagination="{
hideOnClick: true
}"
:breakpoints="{
768: {
slidesPerView: 3,
},
}"
@swiperprogress="onProgress"
@swiperslidechange="onSlideChange"
>
<swiper-slide>Slide 1</swiper-slide>
<swiper-slide>Slide 2</swiper-slide>
<swiper-slide>Slide 3</swiper-slide>
</swiper-container>
</template>
<script>
import { register } from 'swiper/element/bundle';
register();
export default function () {
setup() {
const spaceBetween = 10;
const onProgress = (e) => {
const [swiper, progress] = e.detail;
console.log(progress)
};
const onSlideChange = (e) => {
console.log('slide changed')
}
return {
spaceBetween,
onProgress,
onSlideChange,
};
}
}
</script>
Svelte has full support for web components, including passing attributes as props and listening for custom events:
<script>
import { register } from 'swiper/element/bundle';
register();
const spaceBetween = 10;
const onProgress = (e) => {
const [swiper, progress] = e.detail;
console.log(progress)
};
const onSlideChange = (e) => {
console.log('slide changed')
}
</script>
<swiper-container
slides-per-view={3}
space-between={spaceBetween}
centered-slides={true}
pagination={{
hideOnClick: true,
}}
breakpoints={{
768: {
slidesPerView: 3,
},
}}
on:swiperprogress={onProgress}
on:swiperslidechange={onSlideChange}
>
<swiper-slide>Slide 1</swiper-slide>
<swiper-slide>Slide 2</swiper-slide>
<swiper-slide>Slide 3</swiper-slide>
</swiper-container>
Solid has full support for web components, including passing attributes as props and listening for custom events:
import { register } from 'swiper/element/bundle';
register();
export default () => {
const spaceBetween = 10;
const onProgress = (e) => {
const [swiper, progress] = e.detail;
console.log(progress);
};
const onSlideChange = (e) => {
console.log('slide changed');
};
return (
<swiper-container
slides-per-view={1}
space-between={spaceBetween}
centered-slides={true}
pagination={{
hideOnClick: true,
}}
breakpoints={{
768: {
slidesPerView: 3,
},
}}
onSwiperprogress={onProgress}
onSwiperslidechange={onSlideChange}
>
<swiper-slide>Slide 1</swiper-slide>
<swiper-slide>Slide 2</swiper-slide>
<swiper-slide>Slide 3</swiper-slide>
</swiper-container>
);
};
As you see it is really easy to integrate Swiper into your website or app. So here are your next steps: