# Swiper User Guide

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:

```html
<!-- 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:

```html
<!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](#2-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:

```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"

    ```bash
    npm install swiper
    ```

=== "yarn"

    ```bash
    yarn add swiper
    ```

=== "pnpm"

    ```bash
    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.

### 2.2 Import core + only the modules you need (recommended)

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

```js
// 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:

```js
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)

```html
<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

```js
const swiper = new Swiper(container, options);
```

- `container` — a CSS selector string (e.g. `'.swiper'`) **or** an `HTMLElement`.
- `options` — an optional object of [parameters](#4-configuring-your-slider).

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

```js
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.

```js
// 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)

```js
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

```js
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:

```js
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:

```js
// 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:

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

Alternatively, enable the mutation observer and Swiper updates automatically:

```js
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

```js
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

```js
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](#510-grid-multiple-rows) 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):

```js
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)

```js
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',
  },
});
```

```html
<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)

```js
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
  },
});
```

```html
<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:

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

### 5.3 Scrollbar

```js
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)
  },
});
```

```html
<div class="swiper-scrollbar"></div>
```

### 5.4 Autoplay

```js
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:

```js
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'`.

```js
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

```js
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

```js
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)

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

const swiper = new Swiper('.swiper', {
  modules: [Zoom],
  zoom: { maxRatio: 3, minRatio: 1 },
});
```

```html
<div class="swiper-slide">
  <div class="swiper-zoom-container">
    <img src="photo.jpg" />
  </div>
</div>
```

Drive zoom programmatically through the `zoom` namespace:

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

### 5.9 Thumbnails (thumbs gallery)

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

```js
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)

```js
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:

```js
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)

```js
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:

```js
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`:

```jsx
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

```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:

```html
<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)

### 7.1 A simple image carousel with arrows and dots

```js
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

```js
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

```js
const swiper = new Swiper('.products', {
  slidesPerView: 1.2,
  spaceBetween: 12,
  breakpoints: {
    640:  { slidesPerView: 2.2, spaceBetween: 16 },
    1024: { slidesPerView: 4,   spaceBetween: 24 },
  },
});
```

### 7.4 A thumbnail gallery (main + thumbs)

```js
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:

```js
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`.

### Problem: clicking links inside slides triggers a swipe / doesn't open

**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](https://swiperjs.com).

---

_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. Unofficial; not affiliated with or reviewed by the project._
