Jesse A. Green / notebook

Live demo: the DocCompiler guide library as a static, read-only snapshot (October 2026). No backend, no accounts, nothing to submit.

Swiper User Guide

Generated June 2026 from nolimits4web/swiper at 929c014

AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it.

Swiper is a free, open-source, modern touch slider for the web. It powers carousels, galleries, sliders, and full-screen swipe interfaces with hardware-accelerated transitions and native-feeling touch behavior — and it works with plain HTML/JavaScript, React, Vue, or as a standalone web component, without depending on jQuery or any other library.

This guide takes you from a first slider on the page to advanced multi-module setups: pagination, navigation arrows, autoplay, looping, responsive breakpoints, transition effects, zoom, thumbnails, virtual slides, and more. Every option, method, and class name in this guide is taken directly from Swiper's source.

Note

This guide covers Swiper v12.2.0. Swiper is tree-shakeable and modular: you only ship the features you actually import. Most of this guide is about choosing which modules and options you need.


1. Quick Start

The fastest way to see a working slider. Swiper needs three things: a small, specific HTML structure, its CSS, and a one-line initialization.

1.1 The required HTML structure

Swiper expects a container, a wrapper, and slides — with these exact class names:

<!-- Slider main container -->
<div class="swiper">
  <!-- Additional required wrapper -->
  <div class="swiper-wrapper">
    <!-- Slides -->
    <div class="swiper-slide">Slide 1</div>
    <div class="swiper-slide">Slide 2</div>
    <div class="swiper-slide">Slide 3</div>
  </div>
</div>

Important

The class names swiper, swiper-wrapper, and swiper-slide are the defaults Swiper looks for and styles. You can change them with the wrapperClass, slideClass, and containerModifierClass options, but if you do, you must also adapt the CSS. Most projects keep the defaults.

1.2 Minimal working example (CDN)

You can run Swiper with no build tooling by loading the bundle from a CDN:

<!DOCTYPE html>
<html>
  <head>
    <!-- Swiper bundle CSS (includes all module styles) -->
    <link
      rel="stylesheet"
      href="https://cdn.jsdelivr.net/npm/swiper@12/swiper-bundle.min.css"
    />
    <style>
      .swiper { width: 600px; height: 300px; }
      .swiper-slide {
        display: flex;
        align-items: center;
        justify-content: center;
        background: #f1f1f1;
        font-size: 2rem;
      }
    </style>
  </head>
  <body>
    <div class="swiper">
      <div class="swiper-wrapper">
        <div class="swiper-slide">Slide 1</div>
        <div class="swiper-slide">Slide 2</div>
        <div class="swiper-slide">Slide 3</div>
      </div>
    </div>

    <!-- Swiper bundle JS (includes all modules) -->
    <script src="https://cdn.jsdelivr.net/npm/swiper@12/swiper-bundle.min.js"></script>
    <script>
      const swiper = new Swiper('.swiper', {
        // optional parameters
        direction: 'horizontal',
        loop: true,
      });
    </script>
  </body>
</html>

Open the page and drag the slides with your mouse or finger. That is a complete, working Swiper.

Tip

The bundle build (swiper-bundle.*) ships every module and is the easiest way to start. Once your project is in a bundler (Vite, webpack, Rollup), switch to the core + per-module imports shown in Installation so you only ship what you use.

1.3 You must give the slider a size

Swiper does not invent a height for you. If your slider looks invisible or collapsed, the most common cause is that .swiper has no height. Set a size in CSS:

.swiper {
  width: 100%;
  height: 400px;
}

Warning

A Swiper with no height is the single most frequent "it's not working" issue. Either give .swiper an explicit height, or use the autoHeight: true option so the container grows to fit the active slide.


2. Installation

2.1 Install from npm

npm

npm install swiper

yarn

yarn add swiper

pnpm

pnpm add swiper

The package is published as swiper. It includes TypeScript types out of the box — no separate @types/swiper package is needed.

Note

Swiper requires Node.js >= 4.7.0 to install (per the package's engines field). In practice any modern Node version works; this floor only affects the install step, not the browser runtime.

This is the tree-shakeable path. Import the Swiper core class, the modules you want, and their CSS:

// import Swiper core and required modules
import Swiper from 'swiper';
import { Navigation, Pagination } from 'swiper/modules';

// import Swiper styles
import 'swiper/css';
import 'swiper/css/navigation';
import 'swiper/css/pagination';

// init Swiper
const swiper = new Swiper('.swiper', {
  modules: [Navigation, Pagination],
  // ... other parameters
  navigation: {
    nextEl: '.swiper-button-next',
    prevEl: '.swiper-button-prev',
  },
  pagination: {
    el: '.swiper-pagination',
  },
});

The available import entry points come straight from the package's exports map:

Import What it provides
swiper The Swiper core class (default export)
swiper/modules All feature modules (Navigation, Pagination, Autoplay, …)
swiper/bundle Core + all modules pre-installed (no modules array needed)
swiper/css Core styles (always required)
swiper/css/bundle All module styles in one file
swiper/css/navigation, swiper/css/pagination, … Per-module styles
swiper/react React components (Swiper, SwiperSlide)
swiper/vue Vue components
swiper/element The <swiper-container> web component registration

Tip

Always import swiper/css (the core styles). Then add one swiper/css/<module> import per module that has its own styling — currently: a11y, autoplay, controller, the effect-* modules, free-mode, grid, hash-navigation, history, keyboard, manipulation, mousewheel, navigation, pagination, parallax, scrollbar, thumbs, virtual, and zoom.

2.3 Use the all-in-one bundle

If you don't care about bundle size (e.g. a quick prototype), import the bundle and skip the modules array entirely:

import Swiper from 'swiper/bundle';
import 'swiper/css/bundle';

const swiper = new Swiper('.swiper', {
  // every module is already available
  loop: true,
  navigation: { nextEl: '.swiper-button-next', prevEl: '.swiper-button-prev' },
  pagination: { el: '.swiper-pagination' },
});

2.4 Use from a CDN (no build step)

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/swiper@12/swiper-bundle.min.css" />
<script src="https://cdn.jsdelivr.net/npm/swiper@12/swiper-bundle.min.js"></script>

When loaded this way, Swiper is available as a global, and all modules are already installed.


3. Everyday Usage

This section covers the tasks you'll reach for in almost every project.

3.1 Initialize a slider

const swiper = new Swiper(container, options);
  • container — a CSS selector string (e.g. '.swiper') or an HTMLElement.
  • options — an optional object of parameters.

The returned swiper object is the live instance: you read its state (swiper.activeIndex, swiper.isEnd) and drive it (swiper.slideNext()) through it.

Note

If your selector matches multiple elements, Swiper initializes only the first match. To init many sliders, loop over the elements yourself and call new Swiper(el, options) for each.

3.2 Set how many slides are visible

const swiper = new Swiper('.swiper', {
  slidesPerView: 3,   // show 3 slides at once
  spaceBetween: 20,   // 20px gap between slides
});
  • slidesPerView (default 1) — number of slides visible at the same time. Can be a number, a fractional number (e.g. 3.5 to hint the next slide), or 'auto' to let each slide's own width decide.
  • spaceBetween (default 0) — distance between slides, in px.
// Let each slide size itself (e.g. variable-width cards)
const swiper = new Swiper('.swiper', {
  slidesPerView: 'auto',
  spaceBetween: 10,
});

Tip

Use a fractional slidesPerView like 1.2 or 3.3 to deliberately reveal a sliver of the next slide — a strong visual cue that the carousel is swipeable.

3.3 Change direction (horizontal / vertical)

const swiper = new Swiper('.swiper', {
  direction: 'vertical', // default is 'horizontal'
});

Vertical sliders need an explicit height on .swiper to have room to scroll.

3.4 Center the active slide

const swiper = new Swiper('.swiper', {
  slidesPerView: 3,
  centeredSlides: true,
});

3.5 Navigate from your own code

Every navigation action is a method on the instance:

swiper.slideNext();      // go to next slide
swiper.slidePrev();      // go to previous slide
swiper.slideTo(2);       // go to slide at index 2 (0-based)
swiper.slideTo(2, 0);    // ...with no animation (speed = 0 ms)

When you use loop: true, prefer slideToLoop(realIndex) to target a slide by its real (original) index rather than its shifted loop index.

3.6 React to slide changes

Register event handlers either inline via the on option or with .on() after init:

// Inline
const swiper = new Swiper('.swiper', {
  on: {
    slideChange() {
      console.log('active slide is now', this.activeIndex);
    },
  },
});

// Or after the fact
swiper.on('slideChange', () => {
  console.log('active index:', swiper.activeIndex);
});

The most useful everyday events:

Event Fires when
slideChange The active slide changes (by any means)
reachBeginning The slider reaches the first slide
reachEnd The slider reaches the last slide
transitionStart / transitionEnd A slide animation starts / finishes
click / tap The user clicks or taps the slider

3.7 Update after you change the DOM

If you add, remove, or resize slides yourself, tell Swiper to recalculate:

// after modifying slides manually
swiper.update();

Alternatively, enable the mutation observer and Swiper updates automatically:

const swiper = new Swiper('.swiper', {
  observer: true,         // watch the swiper and its children
  observeParents: true,   // also watch parent elements (e.g. tabs that hide/show)
});

3.8 Destroy a slider

swiper.destroy();                 // remove instance + listeners, keep styles
swiper.destroy(true, true);       // also strip Swiper's inline styles/classes

Use this when you tear down a component or re-init with very different options.


4. Configuring Your Slider

Swiper is configured by the options object you pass to the constructor. Below are the parameters you'll use most often. (For the complete parameter reference — every option, type, and default — see the Admin Guide.)

4.1 Core layout & behavior

Option Default Purpose
slidesPerView 1 Slides visible at once (number or 'auto')
spaceBetween 0 Gap between slides (px)
direction 'horizontal' 'horizontal' or 'vertical'
slidesPerGroup 1 How many slides advance per swipe/click
centeredSlides false Center the active slide
initialSlide 0 Index of the slide shown on init
speed 300 Transition duration (ms)
loop false Infinite continuous loop
rewind false At the end, jump back to start (don't use with loop)
autoHeight false Container height adapts to the active slide
grabCursor false Show a "grab" cursor on hover (desktop nicety)
allowTouchMove true Set false to allow only programmatic navigation

4.2 Looping

const swiper = new Swiper('.swiper', {
  loop: true,
});

Loop mode rearranges slides to create a seamless infinite carousel. Because of how it works, your slide count must satisfy a few rules:

  • At least slidesPerView + slidesPerGroup slides (and one more if centeredSlides is on).
  • A multiple of slidesPerGroup — or enable loopAddBlankSlides to auto-pad.
  • A multiple of grid.rows when using the Grid module — again, loopAddBlankSlides pads for you.

Warning

If you see a console warning about "wrong number of slides for loop mode," you don't have enough slides for a smooth loop. Add more real slides, reduce slidesPerView, or set loopAddBlankSlides: true (the default) so Swiper inserts blank padding slides.

Caution

Do not combine loop: true with rewind: true. They are two different ways to handle reaching the end and are not designed to be used together.

4.3 Responsive breakpoints

Change parameters at different screen widths. Breakpoint keys are min-widths (mobile-first):

const swiper = new Swiper('.swiper', {
  // default (smallest screens)
  slidesPerView: 1,
  spaceBetween: 10,

  breakpoints: {
    // >= 640px
    640: { slidesPerView: 2, spaceBetween: 20 },
    // >= 1024px
    1024: { slidesPerView: 4, spaceBetween: 40 },
  },
});

Note

Only layout-type parameters can change per breakpoint (slidesPerView, slidesPerGroup, spaceBetween, grid.rows, and similar). Parameters that change core behavior or require a different DOM — like loop and effect — cannot be set inside breakpoints.

You can also key breakpoints by ratio ('@0.75', '@1.5') and switch the basis from the window to the container with breakpointsBase: 'container'.


5. Feature Modules

Swiper's optional features are modules. Import the module, add it to the modules array (or use the bundle), and configure it through its matching option. Here are the modules you'll use most.

5.1 Navigation (prev / next arrows)

import { Navigation } from 'swiper/modules';
import 'swiper/css/navigation';

const swiper = new Swiper('.swiper', {
  modules: [Navigation],
  navigation: {
    nextEl: '.swiper-button-next',
    prevEl: '.swiper-button-prev',
  },
});
<div class="swiper">
  <div class="swiper-wrapper">...</div>
  <div class="swiper-button-prev"></div>
  <div class="swiper-button-next"></div>
</div>

Useful navigation options:

Option Default Purpose
nextEl / prevEl null Selector or element for the buttons
hideOnClick false Toggle button visibility on slider click
disabledClass 'swiper-button-disabled' Class added when a button can't be used

5.2 Pagination (dots, fraction, or progress bar)

import { Pagination } from 'swiper/modules';
import 'swiper/css/pagination';

const swiper = new Swiper('.swiper', {
  modules: [Pagination],
  pagination: {
    el: '.swiper-pagination',
    type: 'bullets',   // 'bullets' | 'fraction' | 'progressbar' | 'custom'
    clickable: true,   // let users click a dot to jump to that slide
  },
});
<div class="swiper">
  <div class="swiper-wrapper">...</div>
  <div class="swiper-pagination"></div>
</div>

Pagination highlights:

Option Default Purpose
type 'bullets' 'bullets', 'fraction', 'progressbar', or 'custom'
clickable false Click a bullet to navigate (bullets only)
dynamicBullets false Show only a few bullets when there are many slides
renderBullet(index, className) — Fully custom bullet HTML
renderFraction / renderProgressbar / renderCustom — Custom HTML for the other types

Example custom fraction text:

pagination: {
  el: '.swiper-pagination',
  type: 'fraction',
  renderFraction(currentClass, totalClass) {
    return `<span class="${currentClass}"></span> of <span class="${totalClass}"></span>`;
  },
}

5.3 Scrollbar

import { Scrollbar } from 'swiper/modules';
import 'swiper/css/scrollbar';

const swiper = new Swiper('.swiper', {
  modules: [Scrollbar],
  scrollbar: {
    el: '.swiper-scrollbar',
    draggable: true,   // drag the scrollbar to move the slider
    hide: true,        // auto-hide after interaction (default true)
  },
});
<div class="swiper-scrollbar"></div>

5.4 Autoplay

import { Autoplay } from 'swiper/modules';

const swiper = new Swiper('.swiper', {
  modules: [Autoplay],
  autoplay: {
    delay: 3000,                 // ms between slides (default 3000)
    disableOnInteraction: false, // keep autoplaying after the user swipes
    pauseOnMouseEnter: true,     // pause while hovered
  },
});

Control it at runtime through the autoplay namespace:

swiper.autoplay.start();
swiper.autoplay.stop();
swiper.autoplay.pause();
swiper.autoplay.resume();
console.log(swiper.autoplay.running, swiper.autoplay.timeLeft);

Tip

You can give individual slides a different hold time with a data-swiper-autoplay attribute (in ms): <div class="swiper-slide" data-swiper-autoplay="5000">.

5.5 Transition effects

Set effect and configure the matching <effect>Effect option. Available effects: 'slide' (default), 'fade', 'cube', 'coverflow', 'flip', 'creative', 'cards'.

import { EffectCoverflow } from 'swiper/modules';
import 'swiper/css/effect-coverflow';

const swiper = new Swiper('.swiper', {
  modules: [EffectCoverflow],
  effect: 'coverflow',
  grabCursor: true,
  centeredSlides: true,
  slidesPerView: 'auto',
  coverflowEffect: {
    rotate: 50,
    depth: 100,
    modifier: 1,
    slideShadows: true,
  },
});
Effect Module to import CSS to import Key options
Fade EffectFade swiper/css/effect-fade crossFade
Cube EffectCube swiper/css/effect-cube shadow, slideShadows, shadowOffset, shadowScale
Coverflow EffectCoverflow swiper/css/effect-coverflow rotate, stretch, depth, scale, modifier, slideShadows
Flip EffectFlip swiper/css/effect-flip slideShadows, limitRotation
Cards EffectCards swiper/css/effect-cards rotate, perSlideRotate, perSlideOffset, slideShadows
Creative EffectCreative swiper/css/effect-creative prev/next transforms, limitProgress, perspective

Note

Effects other than 'slide' are not allowed inside breakpoints — pick one effect for the slider's lifetime.

5.6 Keyboard control

import { Keyboard } from 'swiper/modules';

const swiper = new Swiper('.swiper', {
  modules: [Keyboard],
  keyboard: {
    enabled: true,
    onlyInViewport: true,  // only respond when the slider is on screen
    pageUpDown: true,      // also react to PageUp/PageDown
  },
});

5.7 Mousewheel control

import { Mousewheel } from 'swiper/modules';

const swiper = new Swiper('.swiper', {
  modules: [Mousewheel],
  mousewheel: {
    forceToAxis: true,    // only react to wheel motion along the slider's axis
    releaseOnEdges: true, // let the page scroll once at the first/last slide
    sensitivity: 1,
  },
});

5.8 Zoom (pinch / double-tap to zoom images)

import { Zoom } from 'swiper/modules';
import 'swiper/css/zoom';

const swiper = new Swiper('.swiper', {
  modules: [Zoom],
  zoom: { maxRatio: 3, minRatio: 1 },
});
<div class="swiper-slide">
  <div class="swiper-zoom-container">
    <img src="photo.jpg" />
  </div>
</div>

Drive zoom programmatically through the zoom namespace:

swiper.zoom.in();      // zoom into the active slide's image
swiper.zoom.out();
swiper.zoom.toggle();

Wire a small "thumbs" Swiper into a main Swiper so clicking a thumbnail navigates the gallery:

import { Thumbs, Navigation } from 'swiper/modules';
import 'swiper/css/thumbs';

const thumbs = new Swiper('.thumbs-swiper', {
  slidesPerView: 4,
  spaceBetween: 10,
});

const main = new Swiper('.main-swiper', {
  modules: [Thumbs, Navigation],
  thumbs: { swiper: thumbs },
});

5.10 Grid (multiple rows)

import { Grid } from 'swiper/modules';
import 'swiper/css/grid';

const swiper = new Swiper('.swiper', {
  modules: [Grid],
  slidesPerView: 3,
  grid: {
    rows: 2,
    fill: 'row',   // 'row' or 'column' (default 'column')
  },
});

Note

slidesPerView: 'auto' is not compatible with multi-row grids (grid.rows > 1).

5.11 Virtual slides (large data sets)

When you have hundreds of slides, Virtual keeps only the visible ones in the DOM:

import { Virtual } from 'swiper/modules';
import 'swiper/css/virtual';

const swiper = new Swiper('.swiper', {
  modules: [Virtual],
  virtual: {
    slides: ['Slide 1', 'Slide 2', 'Slide 3', /* ...hundreds more */],
  },
});

5.12 Free mode (no snapping)

import { FreeMode } from 'swiper/modules';
import 'swiper/css/free-mode';

const swiper = new Swiper('.swiper', {
  modules: [FreeMode],
  slidesPerView: 'auto',
  freeMode: {
    enabled: true,
    sticky: false,   // set true to snap to slides after a flick
  },
});

5.13 Accessibility (A11y)

The A11y module adds ARIA roles, labels, and screen-reader messages. It is enabled by default when imported:

import { A11y } from 'swiper/modules';
import 'swiper/css/a11y';

const swiper = new Swiper('.swiper', {
  modules: [A11y],
  a11y: {
    prevSlideMessage: 'Previous slide',
    nextSlideMessage: 'Next slide',
    paginationBulletMessage: 'Go to slide {{index}}',
  },
});

Tip

Messages support the placeholders {{index}} and {{slidesLength}}, which Swiper fills in for each slide.

5.14 Other modules at a glance

Module Import What it does
Parallax swiper/modules Parallax-move elements inside slides as you swipe
Controller swiper/modules Make one Swiper drive one or more other Swipers
HashNavigation swiper/modules Reflect the active slide in the URL hash
History swiper/modules Give each slide its own URL via the History API
Manipulation swiper/modules Add/remove slides in core (non-framework) usage

6. Framework Integration

6.1 React

Import the components from swiper/react and the modules from swiper/modules:

import { Swiper, SwiperSlide } from 'swiper/react';
import { Navigation, Pagination } from 'swiper/modules';

import 'swiper/css';
import 'swiper/css/navigation';
import 'swiper/css/pagination';

export default function Gallery() {
  return (
    <Swiper
      modules={[Navigation, Pagination]}
      slidesPerView={3}
      spaceBetween={10}
      navigation
      pagination={{ clickable: true }}
      onSwiper={(swiper) => console.log('ready', swiper)}
      onSlideChange={(swiper) => console.log('slide', swiper.activeIndex)}
    >
      <SwiperSlide>Slide 1</SwiperSlide>
      <SwiperSlide>Slide 2</SwiperSlide>
      <SwiperSlide>Slide 3</SwiperSlide>
    </Swiper>
  );
}
  • Pass every Swiper parameter as a prop (slidesPerView, spaceBetween, navigation, …).
  • Listen for events with on<EventName> props (onSwiper, onSlideChange, onReachEnd, …).
  • Inside a custom slide component, use the useSwiper() and useSwiperSlide() hooks to read the instance and per-slide state (isActive, isVisible, isPrev, isNext).

<SwiperSlide> accepts tag, zoom, lazy, and virtualIndex props, and its children can be a render function receiving { isActive, isVisible, isFullyVisible, isPrev, isNext }.

6.2 Vue

<template>
  <swiper
    :modules="modules"
    :slides-per-view="3"
    :space-between="50"
    navigation
    :pagination="{ clickable: true }"
    @swiper="onSwiper"
    @slideChange="onSlideChange"
  >
    <swiper-slide>Slide 1</swiper-slide>
    <swiper-slide>Slide 2</swiper-slide>
    <swiper-slide>Slide 3</swiper-slide>
  </swiper>
</template>

<script>
import { Swiper, SwiperSlide } from 'swiper/vue';
import { Navigation, Pagination } from 'swiper/modules';

import 'swiper/css';
import 'swiper/css/navigation';
import 'swiper/css/pagination';

export default {
  components: { Swiper, SwiperSlide },
  setup() {
    const onSwiper = (swiper) => { /* save instance */ };
    const onSlideChange = () => { /* react */ };
    return { onSwiper, onSlideChange, modules: [Navigation, Pagination] };
  },
};
</script>

Vue also exposes useSwiper() and useSwiperSlide() composables (returning reactive refs) for use inside child components.

6.3 Web component (<swiper-container>)

Swiper Element is a framework-free custom element. Register it once, then use HTML tags with kebab-case attributes:

<script type="module">
  import { register } from 'swiper/element/bundle';
  register();
</script>

<swiper-container 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>
  • Each SwiperOptions parameter becomes a kebab-case attribute (slidesPerView → slides-per-view).
  • The live instance is on the element: document.querySelector('swiper-container').swiper.
  • Because the element uses the Shadow DOM, inject custom styles with the injectStyles / injectStylesUrls properties, and namespace DOM events with eventsPrefix.

Note

The web component registers two custom elements: <swiper-container> and <swiper-slide>. Use the element/bundle entry for the all-modules build, or swiper/element if you wire modules yourself.


7. Common Tasks (Recipes)

import Swiper from 'swiper';
import { Navigation, Pagination } from 'swiper/modules';
import 'swiper/css';
import 'swiper/css/navigation';
import 'swiper/css/pagination';

const swiper = new Swiper('.swiper', {
  modules: [Navigation, Pagination],
  loop: true,
  navigation: { nextEl: '.swiper-button-next', prevEl: '.swiper-button-prev' },
  pagination: { el: '.swiper-pagination', clickable: true },
});

7.2 An auto-advancing hero banner that pauses on hover

import Swiper from 'swiper';
import { Autoplay, Pagination } from 'swiper/modules';
import 'swiper/css';
import 'swiper/css/pagination';

const swiper = new Swiper('.hero', {
  modules: [Autoplay, Pagination],
  loop: true,
  autoplay: { delay: 5000, pauseOnMouseEnter: true, disableOnInteraction: false },
  pagination: { el: '.swiper-pagination' },
});

7.3 A responsive product grid

const swiper = new Swiper('.products', {
  slidesPerView: 1.2,
  spaceBetween: 12,
  breakpoints: {
    640:  { slidesPerView: 2.2, spaceBetween: 16 },
    1024: { slidesPerView: 4,   spaceBetween: 24 },
  },
});
import Swiper from 'swiper';
import { Thumbs, Navigation } from 'swiper/modules';
import 'swiper/css';
import 'swiper/css/navigation';
import 'swiper/css/thumbs';

const thumbs = new Swiper('.thumbs', { slidesPerView: 5, spaceBetween: 8, watchSlidesProgress: true });
const main = new Swiper('.main', {
  modules: [Thumbs, Navigation],
  navigation: { nextEl: '.swiper-button-next', prevEl: '.swiper-button-prev' },
  thumbs: { swiper: thumbs },
});

7.5 Add and remove slides at runtime (core usage)

With the Manipulation module imported, the instance gains slide-editing methods:

swiper.appendSlide('<div class="swiper-slide">New last</div>');
swiper.prependSlide('<div class="swiper-slide">New first</div>');
swiper.addSlide(2, '<div class="swiper-slide">Inserted at index 2</div>');
swiper.removeSlide(0);          // remove the first slide
swiper.removeSlide([0, 1]);     // remove the first two
swiper.removeAllSlides();

Note

These manipulation methods are for core (vanilla JS) usage. In React and Vue you change your slide data/array instead, and the component re-renders.


8. Best Practices

  • [ ] Import only the modules you use. Core + per-module imports keep your bundle small; the bundle build is for prototypes.
  • [ ] Always import swiper/css plus one swiper/css/<module> per styled module.
  • [ ] Give .swiper an explicit size (or use autoHeight).
  • [ ] Keep the swiper → swiper-wrapper → swiper-slide structure unless you have a strong reason to rename classes.
  • [ ] Call swiper.update() (or enable observer) after you mutate slides outside Swiper.
  • [ ] Enable A11y for any user-facing slider; add meaningful prevSlideMessage / nextSlideMessage.
  • [ ] Mind loop requirements — have enough slides, and keep the count a multiple of slidesPerGroup/grid.rows.
  • [ ] Destroy instances when components unmount to avoid leaks (React/Vue wrappers do this for you).

9. How It Works (Concepts)

You don't need this section to use Swiper, but it helps explain the behavior you'll see.

Slides, wrapper, container. The outer .swiper clips the view. The inner .swiper-wrapper is the strip that actually moves (via CSS transform). Each .swiper-slide is one item. Swiper measures these and computes a grid of snap positions.

Active index vs. real index. swiper.activeIndex is the index in the current DOM order. In loop mode Swiper clones/rearranges slides, so the active index is shifted; swiper.realIndex gives you the original slide's index. Target real slides with slideToLoop().

Progress. swiper.progress runs from 0 (first slide / start) to 1 (last slide / end). The progress event reports it continuously — handy for syncing external animations.

Modules. Core Swiper handles layout, touch, and transitions. Everything else — navigation, pagination, autoplay, effects, zoom — is a module that hooks into Swiper's lifecycle via events. That's why the library is tree-shakeable: unused modules are never imported.

Breakpoints. On resize, Swiper recomputes which breakpoint applies and merges its parameters over the defaults. Only layout-safe parameters can change this way.


10. Troubleshooting

Error: console warning Swiper Loop Warning: The number of slides is not enough for loop mode

Cause: Loop mode needs enough slides to create a seamless wrap, and (for grouped/grid layouts) a slide count that is a multiple of slidesPerGroup / grid.rows. Solution: Add more real slides, lower slidesPerView/slidesPerGroup, or keep loopAddBlankSlides: true (the default) so Swiper pads with blank slides. Prevention: Plan slide counts as a multiple of your group/row size when designing a looped carousel.

Problem: the slider is invisible or has zero height

Cause: .swiper has no height; the wrapper collapses. Solution: Set height (and usually width) on .swiper in CSS, or use autoHeight: true. Prevention: Always style the container before debugging behavior.

Problem: navigation arrows or pagination don't appear

Cause: The module wasn't imported/added to modules, its CSS wasn't imported, or the target element/selector is missing. Solution: Import the module from swiper/modules, add it to the modules array (or use the bundle), import swiper/css/navigation / swiper/css/pagination, and make sure the nextEl/prevEl/el elements exist. Prevention: Treat each module as three pieces: JS import + modules entry + CSS import.

Problem: styles look broken / unstyled slides

Cause: Missing core or module CSS imports. Solution: Import swiper/css always, then swiper/css/<module> for each styled module — or import swiper/css/bundle for everything. Prevention: Add the CSS import next to every module import.

Problem: slides added via JavaScript don't show up

Cause: Swiper hasn't recalculated after the DOM changed. Solution: Call swiper.update(), or use the Manipulation methods (appendSlide, etc.) which update for you, or enable observer: true. Prevention: Enable the observer for sliders whose contents change dynamically.

Problem: vertical slider doesn't scroll

Cause: No height for the vertical track. Solution: Give .swiper an explicit height so there is room to move vertically. Prevention: Pair direction: 'vertical' with a sized container.

Problem: the wrong slide is "active" in loop mode

Cause: You're reading activeIndex, which is shifted by loop clones. Solution: Use swiper.realIndex for the original slide index, and slideToLoop(index) to navigate by real index. Prevention: In loop mode, always think in terms of realIndex.

Cause: Swiper prevents accidental clicks during drags via preventClicks/preventClicksPropagation. Solution: These are true by default to avoid accidental navigation; if you intentionally need raw clicks, evaluate slideToClickedSlide and the preventClicks* options for your case. Prevention: Test interactive content inside slides on touch devices early.

Problem: a slider initialized while hidden has wrong sizes

Cause: Swiper measured a display:none container as zero. Solution: Init after the container is visible, call swiper.update() when it becomes visible, or use observeParents: true to catch show/hide. Prevention: For tabs/accordions, enable observer + observeParents.


11. FAQ

Q: Do I need jQuery or any other library? No. Swiper is fully standalone and library-agnostic.

Q: Does Swiper include TypeScript types? Yes — types ship inside the swiper package. There's no separate types package to install.

Q: How do I keep my bundle small? Import Swiper from swiper, import only the modules you use from swiper/modules, add them to the modules array, and import only the matching swiper/css/<module> files. Swiper is tree-shakeable, so unused modules are dropped.

Q: Bundle build vs. core build — which should I use? Use the bundle (swiper/bundle, swiper/css/bundle) for quick prototypes where size doesn't matter. Use core + modules for production.

Q: Can I use Swiper without a build tool? Yes — load swiper-bundle.min.css and swiper-bundle.min.js from a CDN and use the global Swiper.

Q: How do I make a slider that advances by itself? Import the Autoplay module and set autoplay: { delay: 3000 }.

Q: What's the difference between loop and rewind? loop creates a seamless infinite carousel by rearranging slides. rewind simply jumps from the last slide back to the first (and vice versa) without cloning. Don't use both together.

Q: How do I change settings on mobile vs. desktop? Use the breakpoints option (keyed by min-width). Note that only layout parameters can change per breakpoint — not loop or effect.

Q: How do I control the slider from a button outside it? Keep a reference to the instance and call swiper.slideNext(), swiper.slidePrev(), or swiper.slideTo(index).

Q: How do I get the currently active slide index? Read swiper.activeIndex (or swiper.realIndex in loop mode).

Q: Can one Swiper control another? Yes — import the Controller module and set controller: { control: otherSwiper }.

Q: How do I make image slides zoomable? Import the Zoom module, set zoom: true (or an options object), and wrap each image in <div class="swiper-zoom-container">.

Q: Is Swiper accessible? Yes — import the A11y module (enabled by default) to add ARIA roles, labels, and screen-reader messages. Provide meaningful message strings.

Q: How do I handle hundreds of slides without slowing the page? Use the Virtual module so only the slides near the viewport are kept in the DOM.

Q: How do I clean up a Swiper instance? Call swiper.destroy(). The React and Vue wrappers do this automatically on unmount.

Q: Where is the official site and full API? The project's homepage is swiperjs.com.