# Swiper Admin & Architecture Guide

This guide is the technical reference for engineers, architects, and maintainers who integrate, extend, audit, or build on Swiper. It documents the library's architecture, its complete public API (every parameter, method, property, and event), the build and packaging system, its styling and CSS-class contract, security posture, and a roadmap of known issues and improvements.

It is the companion to the **User Guide** (everyday usage and recipes). Where the User Guide shows how to *use* Swiper, this guide explains how Swiper is *built* and gives the exhaustive reference tables.

> [!NOTE]
> Reference target: **Swiper v12.2.0** (package name `swiper`), MIT-licensed, authored by Vladimir Kharlampidi. Homepage: [swiperjs.com](https://swiperjs.com). This document is derived directly from the TypeScript definitions and source.

---

## 1. Executive Summary

Swiper is a dependency-free, framework-agnostic touch slider for the web. Its defining engineering characteristics:

- **Modular & tree-shakeable.** A small core handles layout, touch, and transitions; every feature (navigation, pagination, autoplay, effects, zoom, …) is an independently importable module. Unused modules never enter your bundle.
- **Multi-target distribution.** One source produces six consumption surfaces: a core ES module, an all-in-one bundle, a React component set, a Vue component set, a Web Component (`<swiper-container>`), and per-module CSS.
- **No runtime dependencies.** Swiper ships zero production dependencies. There is no server, no network I/O, no configuration files, and no secrets — it is a client-side UI library configured entirely by a JavaScript options object.
- **Type-first API.** The authoritative API contract lives in TypeScript declaration files (`.d.ts`) whose JSDoc carries the description, type, default, and examples for every option, method, and event.

| Attribute | Value |
|-----------|-------|
| Package | `swiper` (v12.2.0) |
| License | MIT |
| Module format | ESM (`"type": "module"`) |
| Runtime dependencies | None |
| Install requirement | Node.js `>= 4.7.0` (build/install only) |
| Source layout | All source under `src/`; build emits to `dist/` |
| Build tooling | Rollup + Babel (JS), PostCSS/Less + clean-css/cssnano (CSS), custom Node build scripts |
| Targets | Core, Bundle, React, Vue, Element (web component) |

---

## 2. Architecture

### 2.1 High-level structure

```
                         ┌─────────────────────────────┐
                         │        Swiper core           │
                         │  (src/core/*)                │
                         │  layout · touch · transition │
                         │  translate · update · loop   │
                         └───────────────┬──────────────┘
                                         │ lifecycle events + extendParams()
        ┌────────────────────────────────┼────────────────────────────────┐
        │                                 │                                 │
 ┌──────┴───────┐                 ┌───────┴────────┐                ┌───────┴────────┐
 │  Feature      │                │   Effect        │                │  Integration   │
 │  modules      │                │   modules       │                │  wrappers      │
 │ (src/modules) │                │ (effect-*)      │                │ react/vue/     │
 │ navigation    │                │ fade/cube/flip  │                │ element        │
 │ pagination    │                │ coverflow/cards │                │                │
 │ autoplay …    │                │ creative        │                │                │
 └──────────────┘                 └────────────────┘                └────────────────┘

 dist/ build targets:
   swiper.mjs              core class
   swiper-bundle.mjs       core + all modules
   modules/index.mjs       individual modules (swiper/modules)
   swiper-react.mjs        React components
   swiper-vue.mjs          Vue components
   swiper-element.mjs      <swiper-container> web component
   *.css                   core + per-module styles
```

### 2.2 The core (`src/core`)

The core is responsible for everything that is *not* an optional feature. Its subfolders map directly to responsibilities (all scored HIGH in source triage):

| Core folder | Responsibility |
|-------------|----------------|
| `src/core` | Constructor, parameter merging, init/destroy lifecycle |
| `src/core/events` | Touch/pointer event binding (start/move/end), click handling |
| `src/core/slide` | `slideTo` / `slideNext` / `slidePrev` / `slideReset` / `slideToClosest` logic |
| `src/core/transition` | Transition start/end orchestration |
| `src/core/translate` | Reading/setting the wrapper translate, min/max translate |
| `src/core/update` | Size/slides/progress/classes recalculation |
| `src/core/loop` | Loop slide creation/destruction and "loop fix" |
| `src/core/breakpoints` | Resolving and applying responsive breakpoints |
| `src/core/grab-cursor` | Grab-cursor desktop affordance |
| `src/core/check-overflow` | `watchOverflow` locking when there aren't enough slides |
| `src/core/classes` | Computing CSS classes for container and slides |

### 2.3 The module system

A module is a function conforming to the `SwiperModule` type (from `src/types/shared.d.ts`):

```ts
export type SwiperModule = (options: {
  params: Swiper['params'];
  swiper: Swiper;
  extendParams: (obj: { [name: string]: any }) => void;
  on: Swiper['on'];
  once: Swiper['once'];
  off: Swiper['off'];
  emit: Swiper['emit'];
}) => void;
```

Each module receives the live instance and the event bus. It:

1. Calls `extendParams()` to register its own option object and defaults (e.g. the `navigation` module registers the `navigation` option block).
2. Subscribes to core lifecycle events (`init`, `update`, `slideChange`, `setTranslate`, `resize`, …) via `on()`.
3. Adds its own state/methods to the instance (e.g. `swiper.navigation`, `swiper.autoplay`) and emits its own events (`navigationNext`, `autoplayStart`, …).

Modules are installed either by passing them in the `modules` array per-instance, or globally with the static `Swiper.use([...])`. The **bundle** build pre-installs all of them.

> [!NOTE]
> This is why the User Guide repeatedly frames a feature as "three pieces": the module import (JS), the `modules` array entry (installation), and the CSS import (styling). The architecture enforces that separation to keep the core tiny.

### 2.4 Integration wrappers

| Wrapper | Source | What it adapts |
|---------|--------|----------------|
| React (`src/react`) | `swiper-react.d.ts` | `<Swiper>` / `<SwiperSlide>` components; props mirror `SwiperOptions`; events as `on<Event>` props; `useSwiper()`/`useSwiperSlide()` hooks |
| Vue (`src/vue`) | `swiper-vue.d.ts` | `<swiper>`/`<swiper-slide>` components; props mirror options; `@event` listeners; `useSwiper()`/`useSwiperSlide()` composables (reactive refs) |
| Element (`src/swiper-element.d.ts`) | Web component | `<swiper-container>`/`<swiper-slide>` custom elements; Shadow DOM; kebab-case attributes; `register()` entry |
| Shared (`src/components-shared`, `src/shared`) | — | Code shared across the React/Vue/Element wrappers (param parsing, slot handling, event wiring) |

The wrappers are thin: they translate framework idioms (props, slots, reactivity) into the same core `SwiperOptions` object and instance the User Guide already documented. The React/Vue components additionally manage the instance lifecycle (init on mount, `update` on prop change, `destroy` on unmount).

---

## 3. Packaging & Distribution

### 3.1 The `exports` map (canonical entry points)

The published package's `exports` field (`src/copy/package.json`) is the authoritative list of import specifiers. Engineers should treat it as the contract — only these entry points are public.

| Entry point | `types` | `default` |
|-------------|---------|-----------|
| `swiper` / `swiper/core` | `swiper.d.ts` | `swiper.mjs` |
| `swiper/bundle` | `swiper.d.ts` | `swiper-bundle.mjs` |
| `swiper/effect-utils` | `swiper-effect-utils.d.ts` | `swiper-effect-utils.mjs` |
| `swiper/modules` | `types/modules/index.d.ts` | `modules/index.mjs` |
| `swiper/react` | `swiper-react.d.ts` | `swiper-react.mjs` |
| `swiper/vue` | `swiper-vue.d.ts` | `swiper-vue.mjs` |
| `swiper/element` | `swiper-element.d.ts` | `swiper-element.mjs` |
| `swiper/element/bundle` | `swiper-element.d.ts` | `swiper-element-bundle.mjs` |
| `swiper/css` / `swiper/swiper.css` | `swiper.css.d.ts` | `swiper.css` |
| `swiper/css/bundle` | `swiper-bundle.css.d.ts` | `swiper-bundle.css` |
| `swiper/css/<module>` | `modules/<module>.css.d.ts` | `modules/<module>.css` |
| `swiper/element/css/<module>` | `modules/<module>-element.css.d.ts` | `modules/<module>-element.css` |
| `swiper/types` | `types/index.d.ts` | — |

Per-module CSS entry points exist for: `a11y`, `autoplay`, `controller`, `effect-coverflow`, `effect-cube`, `effect-fade`, `effect-flip`, `effect-creative`, `effect-cards`, `free-mode`, `grid`, `hash-navigation`, `history`, `keyboard`, `manipulation`, `mousewheel`, `navigation`, `pagination`, `parallax`, `scrollbar`, `thumbs`, `virtual`, `zoom` — and the same set again under `swiper/element/css/*` for the Shadow-DOM web component.

> [!IMPORTANT]
> The web component uses **separate** `*-element.css` files (suffixed `-element`) because Shadow-DOM-scoped styling differs from light-DOM styling. When using `<swiper-container>`, inject styles via the element's `injectStyles`/`injectStylesUrls` properties rather than importing global CSS.

### 3.2 Build pipeline

The build is driven by custom Node scripts (`scripts/`), orchestrated through npm scripts in the root `package.json`:

| Command | Purpose |
|---------|---------|
| `npm run build` | Development build → `dist/` |
| `npm run build:prod` | Production build → `dist/` |
| `npm run watch` | Rebuild on source change |
| `npm run core` / `react` / `vue` / `element` | Build + serve the matching playground via Vite |
| `npm run demos` | Build + serve the `demos/` site |
| `npm run lint` | ESLint (airbnb-base + prettier) |
| `npm run check-format` / `format` | Prettier check / write |
| `npm run validate` | `check-format` + `lint` in parallel |
| `npm test` | `validate` then `build:prod` |
| `npm run release` | `validate` then the release script |
| `npm run build-icons-font` | Generate the icon font (Python script) |
| `npm run changelog` | Conventional-changelog (Angular preset) |

Toolchain (from `devDependencies`): **Rollup** (`rollup`, `@rollup/plugin-babel`, `@rollup/plugin-node-resolve`, `@rollup/plugin-replace`) for JS bundling; **Babel** (`@babel/core`, `preset-env`, `preset-react`) for transpilation; **PostCSS** (`postcss`, `postcss-nested`, `autoprefixer`, `cssnano`) and **Less** (`less`) plus `clean-css` for styles; **terser** for minification; **Vite** for the playgrounds.

> [!NOTE]
> Per the README's contribution rule, **all changes go into `src/` only** — `dist/` is generated. The `dist/` folder is what consumers should use in production; `src/` is the editable source of truth.

### 3.3 Build-time flags

The single build-time configuration value found in source is the environment variable `SWIPER_BUILD_MODULES` (read via `process.env` in `scripts/utils/helper.js`). It controls which modules the build script includes when assembling targets. It is a *build* concern only — it has no effect at runtime in the browser.

> [!NOTE]
> Swiper has **no runtime configuration files** and **no runtime environment variables**. All runtime behavior is set through the `SwiperOptions` object passed to the constructor (documented in §4). There is no `.env`, no config schema, and no config loader to manage.

---

## 4. Complete Parameter Reference (`SwiperOptions`)

Every core parameter, its type, and its default — taken verbatim from `src/types/swiper-options.d.ts`. Module-specific option blocks are in §6.

### 4.1 Initialization & lifecycle

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `modules` | `SwiperModule[]` | — | Modules to install on this instance |
| `init` | `boolean` | `true` | Auto-initialize on construction; if `false`, call `swiper.init()` manually |
| `enabled` | `boolean` | `true` | Whether Swiper starts enabled (disabled hides nav and ignores interaction) |
| `runCallbacksOnInit` | `boolean` | `true` | Fire transition/slideChange events during init (when `initialSlide` ≠ 0 or `loop`) |
| `initialSlide` | `number` | `0` | Index of the slide shown initially |
| `direction` | `'horizontal' \| 'vertical'` | `'horizontal'` | Slide axis |
| `speed` | `number` | `300` | Transition duration (ms) |
| `updateOnWindowResize` | `boolean` | `true` | Recalculate on window resize/orientationchange |
| `resizeObserver` | `boolean` | `true` | Use `ResizeObserver` on the container when available |
| `userAgent` | `string \| null` | `null` | UA string for SSR device detection |
| `url` | `string \| null` | `null` | URL for SSR active-slide detection with history |

### 4.2 Slides grid & sizing

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `slidesPerView` | `number \| 'auto'` | `1` | Slides visible at once |
| `slidesPerGroup` | `number` | `1` | Slides advanced per action |
| `slidesPerGroupSkip` | `number` | `0` | First N slides treated as single groups |
| `slidesPerGroupAuto` | `boolean` | `false` | With `slidesPerView:'auto'`, skip all in-view slides per action |
| `spaceBetween` | `number \| string` | `0` | Gap between slides (px) |
| `centeredSlides` | `boolean` | `false` | Center the active slide |
| `centeredSlidesBounds` | `boolean` | `false` | Center without gaps at the edges (needs `centeredSlides`) |
| `slidesOffsetBefore` | `number` | `0` | Extra offset before the first slide (px) |
| `slidesOffsetAfter` | `number` | `0` | Extra offset after the last slide (px) |
| `normalizeSlideIndex` | `boolean` | `true` | Normalize the active slide index |
| `centerInsufficientSlides` | `boolean` | `false` | Center when fewer slides than `slidesPerView` |
| `snapToSlideEdge` | `boolean` | `false` | Always snap to slide edges (fractional/`'auto'` only) |
| `setWrapperSize` | `boolean` | `false` | Set explicit wrapper size (flexbox fallback) |
| `autoHeight` | `boolean` | `false` | Container height follows the active slide |
| `roundLengths` | `boolean` | `false` | Round slide sizes (avoid blurry text) |
| `width` | `number \| null` | `null` | Force width (disables responsiveness) |
| `height` | `number \| null` | `null` | Force height (disables responsiveness) |
| `maxBackfaceHiddenSlides` | `number` | `10` | Threshold for `backface-visibility:hidden` (Safari flicker fix) |

### 4.3 Touch, swipe & resistance

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `grabCursor` | `boolean` | `false` | Show grab cursor on hover |
| `touchEventsTarget` | `'container' \| 'wrapper'` | `'wrapper'` | Element to listen for touch on |
| `touchRatio` | `number` | `1` | Touch movement ratio |
| `touchAngle` | `number` | `45` | Angle (deg) to trigger a touch move |
| `simulateTouch` | `boolean` | `true` | Accept mouse as touch (click-drag) |
| `shortSwipes` | `boolean` | `true` | Enable short swipes |
| `longSwipes` | `boolean` | `true` | Enable long swipes |
| `longSwipesRatio` | `number` | `0.5` | Threshold ratio for long swipes |
| `longSwipesMs` | `number` | `300` | Min duration (ms) for long swipes |
| `followFinger` | `boolean` | `true` | Track finger during drag (vs. animate on release) |
| `allowTouchMove` | `boolean` | `true` | Allow drag-to-slide |
| `threshold` | `number` | `5` | Min touch distance (px) before moving |
| `touchStartPreventDefault` | `boolean` | `true` | `preventDefault` on `pointerdown` |
| `touchStartForcePreventDefault` | `boolean` | `false` | Always `preventDefault` on touchstart |
| `touchMoveStopPropagation` | `boolean` | `false` | Stop propagation of touchmove |
| `edgeSwipeDetection` | `boolean \| string` | `false` | Release events for in-app swipe-back (`'prevent'` to block system) |
| `edgeSwipeThreshold` | `number` | `20` | Edge area (px) for swipe-back |
| `touchReleaseOnEdges` | `boolean` | `false` | Release touch at edges to allow page scroll (needs `threshold:0`) |
| `passiveListeners` | `boolean` | `true` | Use passive listeners where possible |
| `resistance` | `boolean` | `true` | Resistant bounds |
| `resistanceRatio` | `number` | `0.85` | Resistance ratio |
| `preventInteractionOnTransition` | `boolean` | `false` | Block slide change during transition |
| `allowSlidePrev` | `boolean` | `true` | Allow sliding backward |
| `allowSlideNext` | `boolean` | `true` | Allow sliding forward |

### 4.4 Swiping behavior & clicks

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `noSwiping` | `boolean` | `true` | Disable swiping on `noSwipingClass` elements |
| `noSwipingClass` | `string` | `'swiper-no-swiping'` | Class that disables swiping |
| `noSwipingSelector` | `string` | — | Selector to disable swiping on (e.g. `'input'`) |
| `swipeHandler` | `CSSSelector \| HTMLElement \| null` | `null` | Restrict swiping to this handle |
| `preventClicks` | `boolean` | `true` | Prevent accidental clicks during swipe |
| `preventClicksPropagation` | `boolean` | `true` | Stop click propagation during swipe |
| `slideToClickedSlide` | `boolean` | `false` | Clicking a slide transitions to it |
| `focusableElements` | `string` | `'input, select, option, textarea, button, video, label'` | Elements where swiping is disabled when focused |
| `uniqueNavElements` | `boolean` | `true` | Resolve nav/pagination/scrollbar selectors within children first |

### 4.5 Progress, loop & rewind

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `watchSlidesProgress` | `boolean` | `false` | Compute each slide's progress/visibility (adds `visible` class) |
| `loop` | `boolean` | `false` | Continuous loop mode |
| `loopAddBlankSlides` | `boolean` | `true` | Auto-add blank slides for grid/group evenness in loop |
| `loopAdditionalSlides` | `number` | `0` | Increase number of looped slides |
| `loopPreventsSliding` | `boolean` | `true` | Ignore slideNext/Prev while animating in loop |
| `rewind` | `boolean` | `false` | Rewind at edges (don't combine with `loop`) |

### 4.6 Effects (selector + per-effect blocks)

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `effect` | `'slide' \| 'fade' \| 'cube' \| 'coverflow' \| 'flip' \| 'creative' \| 'cards' \| string` | `'slide'` | Active transition effect |
| `virtualTranslate` | `boolean` | `false` | Operate without setting real translate (custom transitions) |
| `cssMode` | `boolean` | `false` | Use native CSS Scroll Snap (see note below) |

> [!WARNING]
> `cssMode: true` swaps Swiper's JS-driven movement for the browser's CSS Scroll Snap. It can be much faster for simple sliders but **does not support**: Cube effect; the `speed` parameter may have no effect; transition start/end events (use `slideChange`); limited `slidesPerGroup`; `simulateTouch`/mouse-drag; `resistance`; `allowSlidePrev/Next`; and `swipeHandler`. With 3D effects you must wrap slide content in `<div class="swiper-slide-transform">`.

The per-effect option objects (`fadeEffect`, `cubeEffect`, `coverflowEffect`, `flipEffect`, `cardsEffect`, `creativeEffect`) are fully documented in §6.

### 4.7 Responsive & observation

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `breakpoints` | `{ [width:number]: SwiperOptions; [ratio:string]: SwiperOptions }` | — | Per-breakpoint parameter overrides (layout params only) |
| `breakpointsBase` | `'window' \| 'container' \| CSSSelector` | `'window'` | Basis for breakpoint keys |
| `observer` | `boolean` | `false` | MutationObserver on swiper + elements |
| `observeParents` | `boolean` | `false` | Also observe parent elements |
| `observeSlideChildren` | `boolean` | `false` | Also observe slide children |
| `watchOverflow` | `boolean` | `true` | Lock/disable when there aren't enough slides |

### 4.8 Element / Web Component parameters

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `createElements` | `boolean` | `false` | Auto-create wrapper/nav/pagination/scrollbar elements |
| `eventsPrefix` | `string` | `'swiper'` | Prefix for DOM events emitted by `<swiper-container>` |
| `swiperElementNodeName` | `string` | `'SWIPER-CONTAINER'` | Node name used to detect web-component rendering |
| `injectStyles` | `string[]` | — | Inline styles injected into the Shadow DOM |
| `injectStylesUrls` | `string[]` | — | Stylesheet `<link>`s injected into the Shadow DOM |

### 4.9 CSS class-name parameters (namespacing)

Each of these overrides a default Swiper CSS class. Defaults shown; changing them requires matching CSS changes. (Marked `*` are **not** supported in the React/Vue components.)

| Parameter | Default |
|-----------|---------|
| `containerModifierClass` | `'swiper-'` |
| `slideClass` * | `'swiper-slide'` |
| `slideActiveClass` * | `'swiper-slide-active'` |
| `slideVisibleClass` * | `'swiper-slide-visible'` |
| `slideFullyVisibleClass` * | `'swiper-slide-fully-visible'` |
| `slideNextClass` * | `'swiper-slide-next'` |
| `slidePrevClass` * | `'swiper-slide-prev'` |
| `slideBlankClass` * | `'swiper-slide-blank'` |
| `wrapperClass` * | `'swiper-wrapper'` |
| `lazyPreloaderClass` | `'swiper-lazy-preloader'` |
| `lazyPreloadPrevNext` | `0` |

### 4.10 Event registration parameters

| Parameter | Type | Description |
|-----------|------|-------------|
| `on` | `{ [event]: handler }` | Register event handlers at init (see §5 for the event list) |
| `onAny` | `(handler) => void` | Catch-all handler invoked for every event |

> [!NOTE] Negative knowledge
> The following do **not** exist as core options and should never be documented as such: there is no `lazy` core option (lazy loading is handled via `lazyPreloadPrevNext` + the `swiper-lazy-preloader` element and per-slide markup), no `autoplay` core boolean independent of the Autoplay module, and no top-level `navigation`/`pagination`/`scrollbar` behavior without importing the matching module. The only build-time variable is `SWIPER_BUILD_MODULES`; there are no runtime env vars.

---

## 5. Complete Events Reference

Core events from `src/types/swiper-events.d.ts`. Handlers receive the `swiper` instance as the first argument (plus any listed extras). Register via the `on` option, `swiper.on(name, handler)`, `.once()`, or `.off()`.

### 5.1 Lifecycle events

| Event | Extra args | Fires |
|-------|-----------|-------|
| `beforeInit` | — | Right before init |
| `init` | — | After init (with `swiper.on('init')`, only when `init:false`) |
| `afterInit` | — | Right after init |
| `beforeDestroy` | — | Before destroy |
| `destroy` | — | On destroy |
| `update` | — | After `swiper.update()` |

### 5.2 Slide-change events

| Event | Fires |
|-------|-------|
| `slideChange` | Active slide changed |
| `beforeSlideChangeStart` | Before slide-change starts |
| `slideChangeTransitionStart` / `slideChangeTransitionEnd` | Slide-change animation start / end |
| `slideNextTransitionStart` / `slideNextTransitionEnd` | Forward-direction only |
| `slidePrevTransitionStart` / `slidePrevTransitionEnd` | Backward-direction only |
| `slideResetTransitionStart` / `slideResetTransitionEnd` | Reset-to-current animation start / end |
| `activeIndexChange` | `activeIndex` changed |
| `snapIndexChange` | `snapIndex` changed |
| `realIndexChange` | `realIndex` changed (loop) |

### 5.3 Transition & translate events

| Event | Extra args | Fires |
|-------|-----------|-------|
| `beforeTransitionStart` | `speed`, `internal` | Before a transition starts |
| `transitionStart` / `transitionEnd` | — | Transition start / end |
| `setTranslate` | `translate` | Wrapper position changed |
| `setTransition` | `transition` | Animation duration set |
| `momentumBounce` | — | Momentum bounce occurred |

### 5.4 Pointer / interaction events

Each receives `(swiper, event)` where `event` is a `MouseEvent \| TouchEvent \| PointerEvent` (except `sliderFirstMove`, which receives a `TouchEvent`):

`touchStart`, `touchMove`, `touchMoveOpposite`, `sliderMove`, `sliderFirstMove`, `touchEnd`, `click`, `tap`, `doubleTap`, `doubleClick`.

### 5.5 Position / edge events

| Event | Extra args | Fires |
|-------|-----------|-------|
| `progress` | `progress` (0–1) | Progress changed |
| `reachBeginning` | — | Reached the first slide |
| `reachEnd` | — | Reached the last slide |
| `toEdge` | — | Moved to an edge |
| `fromEdge` | — | Moved away from an edge |
| `lock` / `unlock` | — | Locked / unlocked (via `watchOverflow`) |

### 5.6 Layout / structural events

| Event | Extra args | Fires |
|-------|-----------|-------|
| `slidesUpdated` | — | Slides + sizes recalculated |
| `slidesLengthChange` | — | Number of slides changed |
| `slidesGridLengthChange` | — | Slides grid changed |
| `snapGridLengthChange` | — | Snap grid changed |
| `resize` / `beforeResize` | — | On resize handling |
| `orientationchange` | — | Device orientation changed |
| `observerUpdate` | — | Observer detected DOM mutation |
| `breakpoint` | `breakpointParams` | Breakpoint changed |
| `beforeLoopFix` / `loopFix` | — | Around loop rearrangement |
| `changeDirection` | — | Direction changed |

> [!NOTE]
> Events prefixed with `_` (e.g. `_beforeBreakpoint`, `_containerClasses`, `_slideClass`, `_swiper`, `_freeModeNoMomentumRelease`) are **internal**. They are emitted for internal/integration plumbing and are not part of the stable public API — do not rely on them.

Module events (e.g. `autoplayStart`, `navigationNext`, `paginationRender`, `zoomChange`, `hashChange`, `scrollbarDragMove`, `keyPress`, `scroll`) are listed with their modules in §6.

---

## 6. Module Reference

For each module: its option object (with defaults), the instance methods it adds, and the events it emits. Source: `src/types/modules/*.d.ts`.

### 6.1 Navigation

**Options:** `enabled?`, `nextEl`/`prevEl` (`null`), `addIcons` (`true`), `hideOnClick` (`false`), `disabledClass` (`'swiper-button-disabled'`), `hiddenClass` (`'swiper-button-hidden'`), `lockClass` (`'swiper-button-lock'`), `navigationDisabledClass` (`'swiper-navigation-disabled'`).
**Instance (`swiper.navigation`):** `nextEl`, `prevEl`, `update()`, `init()`, `destroy()`.
**Events:** `navigationShow`, `navigationHide`, `navigationPrev`, `navigationNext`.

### 6.2 Pagination

**Options:** `enabled?`, `el` (`null`), `type` (`'bullets'`), `bulletElement` (`'span'`), `dynamicBullets` (`false`), `dynamicMainBullets` (`1`), `hideOnClick` (`true`), `clickable` (`false`), `progressbarOpposite` (`false`), render hooks `renderBullet`/`renderFraction`/`renderProgressbar`/`renderCustom`, `formatFractionCurrent`/`formatFractionTotal`, plus class names: `bulletClass` (`'swiper-pagination-bullet'`), `bulletActiveClass` (`'swiper-pagination-bullet-active'`), `modifierClass` (`'swiper-pagination-'`), `currentClass`, `totalClass`, `hiddenClass`, `progressbarFillClass`, `progressbarOppositeClass`, `clickableClass`, `lockClass`, `horizontalClass`, `verticalClass`, `paginationDisabledClass`.
**Instance (`swiper.pagination`):** `el`, `bullets[]`, `render()`, `update()`, `init()`, `destroy()`.
**Events:** `paginationRender`, `paginationUpdate`, `paginationShow`, `paginationHide`.

### 6.3 Scrollbar

**Options:** `enabled?`, `el` (`null`), `hide` (`true`), `draggable` (`false`), `snapOnRelease` (`false`), `dragSize` (`'auto'`), `lockClass` (`'swiper-scrollbar-lock'`), `dragClass` (`'swiper-scrollbar-drag'`), `scrollbarDisabledClass`, `horizontalClass`, `verticalClass`.
**Instance (`swiper.scrollbar`):** `el`, `dragEl`, `updateSize()`, `setTranslate()`, `init()`, `destroy()`.
**Events:** `scrollbarDragStart`, `scrollbarDragMove`, `scrollbarDragEnd` (each receives the pointer event).

### 6.4 Autoplay

**Options:** `delay` (`3000`), `stopOnLastSlide` (`false`), `disableOnInteraction` (`true`), `reverseDirection` (`false`), `waitForTransition` (`true`), `pauseOnMouseEnter` (`false`).
**Instance (`swiper.autoplay`):** `running`, `paused`, `timeLeft`, `start()`, `stop()`, `pause()`, `resume()`.
**Events:** `autoplayStart`, `autoplayStop`, `autoplayPause`, `autoplayResume`, `autoplay`, `autoplayTimeLeft(swiper, timeLeft, percentage)`.
Per-slide override: `data-swiper-autoplay="<ms>"`.

### 6.5 Keyboard

**Options:** `enabled` (`false`), `onlyInViewport` (`true`), `pageUpDown` (`true`), `speed`.
**Instance (`swiper.keyboard`):** `enabled`, `enable()`, `disable()`.
**Events:** `keyPress(swiper, keyCode)`.

### 6.6 Mousewheel

**Options:** `enabled` (`false`), `forceToAxis` (`false`), `releaseOnEdges` (`false`), `invert` (`false`), `sensitivity` (`1`), `eventsTarget` (`'container'`), `thresholdDelta` (`null`), `thresholdTime` (`null`), `noMousewheelClass` (`'swiper-no-mousewheel'`).
**Instance (`swiper.mousewheel`):** `enabled`, `enable()`, `disable()`.
**Events:** `scroll(swiper, WheelEvent)`.

### 6.7 Zoom

**Options:** `limitToOriginalSize` (`false`), `maxRatio` (`3`), `minRatio` (`1`), `panOnMouseMove` (`false`), `toggle` (`true`), `containerClass` (`'swiper-zoom-container'`), `zoomedSlideClass` (`'swiper-slide-zoomed'`).
**Instance (`swiper.zoom`):** `enabled`, `scale`, `enable()`, `disable()`, `in(ratio?)`, `out()`, `toggle(event?)`.
**Events:** `zoomChange(swiper, scale, imageEl, slideEl)`.

### 6.8 Thumbs

**Options:** `swiper` (`null` — a Swiper instance, selector, or params), `slideThumbActiveClass` (`'swiper-slide-thumb-active'`), `thumbsContainerClass` (`'swiper-thumbs'`), `multipleActiveThumbs` (`true`), `autoScrollOffset` (`0`).
**Instance (`swiper.thumbs`):** `swiper`, `update(initial, p?)`, `init()`.

### 6.9 Virtual

**Options:** `enabled` (`false`), `slides` (`[]`), `slidesPerViewAutoSlideSize` (`320`), `cache` (`true`), `addSlidesBefore` (`0`), `addSlidesAfter` (`0`), `renderSlide` (`null`), `renderExternal` (`null`), `renderExternalUpdate` (`true`).
**Instance (`swiper.virtual`):** `cache`, `from`, `to`, `slides[]`, `appendSlide()`, `prependSlide()`, `removeSlide()`, `removeAllSlides()`, `update(force)`.

### 6.10 Free Mode

**Options:** `enabled` (`false`), `momentum` (`true`), `momentumRatio` (`1`), `momentumVelocityRatio` (`1`), `momentumBounce` (`true`), `momentumBounceRatio` (`1`), `minimumVelocity` (`0.02`), `sticky` (`false`).
**Instance (`swiper.freeMode`):** `onTouchMove()`, `onTouchEnd()`.

### 6.11 Grid

**Options:** `rows` (`1`), `fill` (`'column'` — `'row'` or `'column'`).

### 6.12 Controller

**Options:** `control` (Swiper instance(s), selector, or element — `null`), `inverse` (`false`), `by` (`'slide'` — `'slide'` or `'container'`).
**Instance (`swiper.controller`):** `control`.

### 6.13 A11y

**Options (enabled by default):** `enabled` (`true`), `prevSlideMessage` (`'Previous slide'`), `nextSlideMessage` (`'Next slide'`), `firstSlideMessage` (`'This is the first slide'`), `lastSlideMessage` (`'This is the last slide'`), `paginationBulletMessage` (`'Go to slide {{index}}'`), `notificationClass` (`'swiper-notification'`), `containerMessage` (`null`), `containerRoleDescriptionMessage` (`null`), `containerRole` (`null`), `itemRoleDescriptionMessage` (`null`), `slideLabelMessage` (`'{{index}} / {{slidesLength}}'`), `slideRole` (`'group'`), `id` (`null`), `scrollOnFocus` (`true`), `wrapperLiveRegion` (`true`).
Placeholders: `{{index}}`, `{{slidesLength}}`.

### 6.14 Hash Navigation

**Options:** `watchState` (`false`), `replaceState` (`false`), `getSlideIndex(swiper, hash)` (for virtual slides).
**Events:** `hashChange`, `hashSet`.

### 6.15 History

**Options:** `enabled` (`false`), `root` (`''`), `replaceState` (`false`), `key` (`'slides'`), `keepQuery` (`false`).
Per-slide URL segment via `data-history="<value>"`.

### 6.16 Parallax

**Options:** `enabled` (`false`). Parallaxed elements inside slides use `data-swiper-parallax*` attributes.

### 6.17 Manipulation (core only)

Adds slide-editing methods to the instance: `appendSlide()`, `prependSlide()`, `addSlide(index, slides)`, `removeSlide(indexOrIndexes)`, `removeAllSlides()`. Accepts HTML strings or `HTMLElement`(s). In React/Vue, manipulate the data source instead.

### 6.18 Effect modules

| Module | Options (defaults) |
|--------|--------------------|
| `EffectFade` | `crossFade` (`false`) |
| `EffectCube` | `slideShadows` (`true`), `shadow` (`true`), `shadowOffset` (`20`), `shadowScale` (`0.94`) |
| `EffectCoverflow` | `slideShadows` (`true`), `rotate` (`50`), `stretch` (`0`, number or `%`), `depth` (`100`), `scale` (`1`), `modifier` (`1`) |
| `EffectFlip` | `slideShadows` (`true`), `limitRotation` (`true`) |
| `EffectCards` | `slideShadows` (`true`), `rotate` (`true`), `perSlideRotate` (`2`), `perSlideOffset` (`8`) |
| `EffectCreative` | `prev`/`next` transform objects, `limitProgress` (`1`), `shadowPerProgress` (`false`), `progressMultiplier` (`1`), `perspective` (`true`) |

The `EffectCreative` `prev`/`next` transform shape: `{ translate?: (string|number)[]; rotate?: number[]; opacity?: number; scale?: number; shadow?: boolean; origin?: string }`.

---

## 7. Instance API (`Swiper` class)

From `src/types/swiper-class.d.ts`.

### 7.1 Construction & statics

```ts
new Swiper(container: CSSSelector | HTMLElement, options?: SwiperOptions)
```

| Static | Purpose |
|--------|---------|
| `Swiper.use(modules)` | Install modules globally |
| `Swiper.defaults` | The default options object |
| `Swiper.extendDefaults(options)` | Extend global defaults |
| `Swiper.extendedDefaults` | Current global extended defaults |

### 7.2 Navigation methods

| Method | Returns | Purpose |
|--------|---------|---------|
| `slideNext(speed?, runCallbacks?)` | `boolean` | Go to next slide |
| `slidePrev(speed?, runCallbacks?)` | `boolean` | Go to previous slide |
| `slideTo(index, speed?, runCallbacks?)` | `boolean` | Go to a specific index |
| `slideToLoop(index, speed?, runCallbacks?)` | `Swiper` | Go to a slide by real index (loop) |
| `slideReset(speed?, runCallbacks?)` | `boolean` | Reset to the active slide |
| `slideToClosest(speed?, runCallbacks?)` | `boolean` | Snap to the closest slide |
| `setProgress(progress, speed?)` | `void` | Set translate progress (0–1) |

### 7.3 Update / layout methods

`update()`, `updateSize()`, `updateSlides()`, `updateProgress()`, `updateSlidesClasses()`, `updateAutoHeight(speed?)`, `slidesPerViewDynamic()`, `changeDirection(direction?, needUpdate?)`, `changeLanguageDirection('rtl' | 'ltr')`.

### 7.4 Translate methods

`setTranslate(value)`, `getTranslate()`, `translateTo(translate, speed, runCallbacks?, translateBounds?)`, `minTranslate()`, `maxTranslate()`, `setGrabCursor()`, `unsetGrabCursor()`.

### 7.5 Lifecycle & events methods

`init(el?)`, `destroy(deleteInstance?, cleanStyles?)`, `enable()`, `disable()`, `attachEvents()`, `detachEvents()`, `on(event, handler)`, `once(event, handler)`, `off(event, handler?)`, `emit(event, ...args)`, `onAny(handler)`, `offAny(handler)`.

### 7.6 Key instance properties (read state)

| Property | Type | Meaning |
|----------|------|---------|
| `params` / `originalParams` | `SwiperOptions` | Effective / original options |
| `el` / `wrapperEl` / `slidesEl` | `HTMLElement` | Container / wrapper / slides container |
| `slides` | `HTMLElement[]` | Slide elements |
| `width` / `height` | `number` | Container size |
| `translate` | `number` | Current wrapper translate |
| `progress` | `number` | 0–1 progress |
| `activeIndex` | `number` | Active slide index (DOM order) |
| `realIndex` | `number` | Active slide real index (loop) |
| `previousIndex` / `snapIndex` | `number` | Previous active / current snap index |
| `snapGrid` / `slidesGrid` / `slidesSizesGrid` | `number[]` | Computed grids |
| `isBeginning` / `isEnd` | `boolean` | At first / last position |
| `isLocked` | `boolean` | Locked by `watchOverflow` |
| `animating` | `boolean` | In transition |
| `swipeDirection` | `'prev' \| 'next'` | Current swipe direction |
| `touches` | `{ startX, startY, currentX, currentY, diff }` | Touch state |
| `clickedIndex` / `clickedSlide` | `number` / `HTMLElement` | Last clicked slide |
| `allowSlideNext` / `allowSlidePrev` / `allowTouchMove` | `boolean` | Writable gates |
| `enabled` | `boolean` | Instance enabled |
| Module namespaces | object | `swiper.navigation`, `swiper.pagination`, `swiper.autoplay`, `swiper.zoom`, `swiper.thumbs`, `swiper.virtual`, etc. (present when the module is installed) |

> [!NOTE]
> Properties documented `!INTERNAL` in the source (`loopedSlides`, `rtlTranslate`, `currentBreakpoint`, `destroyed`, `modules`, `loopCreate()`, `loopDestroy()`, `isHorizontal()`, `getBreakpoint()`, `setBreakpoint()`) are implementation details and not part of the supported public API.

---

## 8. Styling & CSS Contract

### 8.1 Required structure & default classes

```html
<div class="swiper">
  <div class="swiper-wrapper">
    <div class="swiper-slide">...</div>
    <div class="swiper-slide">...</div>
  </div>
  <!-- optional module elements -->
  <div class="swiper-button-prev"></div>
  <div class="swiper-button-next"></div>
  <div class="swiper-pagination"></div>
  <div class="swiper-scrollbar"></div>
</div>
```

Swiper computes state classes on slides at runtime: `swiper-slide-active`, `swiper-slide-next`, `swiper-slide-prev`, `swiper-slide-visible`, `swiper-slide-fully-visible`, `swiper-slide-blank`, `swiper-slide-zoomed`, and container modifier classes prefixed `swiper-` (direction, effect, RTL, locked, etc.). Module elements get their own state classes (e.g. `swiper-button-disabled`, `swiper-pagination-bullet-active`).

### 8.2 Light DOM vs Shadow DOM

Two parallel CSS sets exist:

- **Light DOM** (`swiper/css`, `swiper/css/<module>`) — for the core/React/Vue usage where slides are in the normal document.
- **Shadow DOM** (`swiper/element/css/<module>`, files suffixed `-element`) — for the `<swiper-container>` web component, whose internals are encapsulated. Inject these via `injectStyles`/`injectStylesUrls`.

> [!IMPORTANT]
> A recurring community request (issue #8164) asks Swiper to ship its built-in classes at **0 CSS specificity** so apps can override them more easily. When theming, prefer overriding via the documented class-name parameters (§4.9) or layering your own classes rather than fighting specificity.

---

## 9. Security

Swiper is a client-side UI library: it has **no server component, no network calls, no filesystem access, no credentials, and no environment-variable configuration**. The attack surface is therefore limited to what runs in the user's browser when slides and options are rendered. Key considerations:

### 9.1 Known vulnerability class — prototype pollution

The project's issue tracker shows active security work in the **prototype pollution** class:

- **#8189 — "Incomplete Fix for CVE-2026-27212"** (open): indicates a follow-up to a previously addressed CVE; the fix was reported as incomplete and is under review.
- **#8167 — "Can you backport the prototype pollution fix to v11?"** (closed): a prototype-pollution fix landed and a backport to the v11 line was requested.

**Implication for integrators:**

> [!CAUTION]
> Prototype-pollution issues in a slider typically arise when **untrusted data is merged into the options object** (deep-merge of attacker-controlled keys like `__proto__`). If you build Swiper options from user-supplied or third-party JSON, sanitize keys before passing them to `new Swiper(...)`, and **stay on the latest patched v12.x release**. Track [issue #8189](https://github.com/nolimits4web/swiper/issues/8189) for the current state of CVE-2026-27212.

### 9.2 DOM injection through render hooks

Several options accept HTML strings or render functions that produce HTML: `pagination.renderBullet/renderFraction/renderProgressbar/renderCustom`, `virtual.renderSlide/renderExternal`, and the Manipulation methods (`appendSlide`, `prependSlide`, `addSlide`) accept raw HTML strings.

> [!WARNING]
> Treat all of these as `innerHTML` sinks. **Never** pass unescaped user content into render hooks or `appendSlide`/`addSlide`. Escape or sanitize first, or build `HTMLElement`s yourself rather than passing HTML strings.

### 9.3 Web component & Shadow DOM

The `<swiper-container>` element injects styles into a Shadow Root. One closed community issue (#8169) reported a `NotAllowedError` setting `adoptedStyleSheets` on a `ShadowRoot` in certain environments — a robustness rather than confidentiality concern, but worth noting for constrained runtimes (e.g. some embedded/CSP-restricted contexts).

### 9.4 Hardening checklist

- [ ] Pin to the latest patched `swiper@12` release; watch the tracker for CVE follow-ups.
- [ ] Sanitize any externally sourced data before it reaches the options object (guard against `__proto__`/`constructor` keys).
- [ ] Sanitize/escape content used in `renderBullet`/`renderSlide`/`appendSlide`/`addSlide`.
- [ ] Apply a Content Security Policy; Swiper does not require `eval` or remote script.
- [ ] If embedding via the web component, verify `adoptedStyleSheets` support in your target runtimes.

---

## 10. Performance Tuning

| Lever | Effect |
|-------|--------|
| Core + per-module imports | Smallest bundle; the bundle build ships every module |
| `Virtual` module | Keeps only near-viewport slides in the DOM for large data sets |
| `lazyPreloadPrevNext` | Limit preloaded neighbor slides |
| `cssMode: true` | Offload movement to native CSS Scroll Snap (with the feature caveats in §4.6) |
| `resizeObserver` (default on) | Cheaper container-resize detection than window resize |
| `observer`/`observeParents` | Use only when contents actually change; mutation observation has a cost |
| `roundLengths` | Avoids sub-pixel blur; minor cost |
| `maxBackfaceHiddenSlides` | Tune the Safari flicker workaround; keep low on huge slide counts |
| `watchSlidesProgress` | Enables per-slide visibility classes — only enable if you use them |

> [!TIP]
> For content- or image-heavy carousels with many slides, the highest-impact change is the `Virtual` module. For simple sliders that don't need Swiper's richer features, `cssMode` can substantially reduce JS work.

---

## 11. Development & Contributing

- **Edit source only.** Per the README, all changes go into `src/`; `dist/` is generated and must not be hand-edited.
- **Source of truth for the API** is the TypeScript declarations under `src/types/` — option/method/event descriptions and defaults live in their JSDoc.
- **Validate before committing:** `npm run validate` (Prettier check + ESLint). The full `npm test` runs validate then a production build.
- **Playgrounds:** `npm run core | react | vue | element` build and serve the matching example app under `playground/` via Vite; `npm run demos` serves the broader `demos/` site. Use these to manually verify behavior across all four targets.
- **Releases:** `npm run release` runs validation then the release script; `npm run changelog` regenerates `CHANGELOG.md` using the Angular conventional-changelog preset.
- **Conventions:** ESLint (airbnb-base) + Prettier are enforced; the codebase is ESM-only.

---

## 12. Known Issues & Improvement Areas

Drawn from the project's issue tracker (community-reported). These reflect real, open friction points an integrator may encounter and a maintainer may prioritize.

### 12.1 Loop mode

Loop mode is the most frequent source of open issues:

- **#8076** — loop mode not working correctly in some configurations.
- **#7586** — Swiper warns about a "wrong number of slides for loop mode" even when the count seems valid.
- **#8178** — `loopAdditionalSlides` doesn't behave as expected in certain conditions.
- **#7478 / #8095** — `slideToClickedSlide` + `centeredSlides` + `loop` interactions break the loop or block link clicks.
- **#7254** — request to set a fixed number of duplicated slides to stabilize loop behavior.

> [!NOTE]
> The recurring theme: loop's slide-rearrangement interacts badly with `centeredSlides`, `slideToClickedSlide`, and fractional `slidesPerView`. When auditing a looped slider, test these combinations explicitly and prefer `realIndex`/`slideToLoop` in app code.

### 12.2 Accessibility

- **#8181** — improve accessibility in loop mode.
- **#7975** — redundant `aria-disabled` added alongside the native `disabled` attribute on navigation buttons.
- **#5844** — option to disable the `span.swiper-notification` live region.

### 12.3 Web component (Element) parity

- **#8125** — `<swiper-container>` doesn't render the last two slides with `loop` + `slidesPerView="auto"` + custom slide width.
- **#7151** — pagination dots malfunction in loop mode in the Svelte/Element integration.
- **#8173** — request to expose `isEnd`/`isBeginning` state on the host element for CSS styling.

### 12.4 Effects & rendering

- **#8168** — Cube (and possibly other) effects show graphics glitches on Electron/WebKit.
- **#8161** — pagination button icons slightly clipped.

### 12.5 Feature requests of note

- **#8086 / #6882** — desktop zoom and single-click zoom enhancements.
- **#8174** — expose `isFullyVisible` in the React `SwiperSlide` render props.
- **#8164** — ship built-in classes at 0 specificity for easier overriding.

### 12.6 Maintainer-facing observations

- **Loop semantics need clearer guardrails.** Several issues stem from users not satisfying loop's slide-count requirements; surfacing the requirement earlier (or auto-correcting more aggressively than `loopAddBlankSlides`) would reduce churn.
- **Element/web-component parity lags the React/Vue wrappers** in a few cases (last-slides rendering, pagination in loop, exposing state to the host). Integrators targeting the web component should test the specific feature combinations above.
- **Security follow-through.** With an open "incomplete fix" on a CVE (#8189), integrators should pin to the latest patch and maintainers should prioritize closing the prototype-pollution thread and backports.

---

## 13. Quick Reference

| Need | Do |
|------|-----|
| Install | `npm install swiper` |
| Core import | `import Swiper from 'swiper'` + `import 'swiper/css'` |
| Add a module | `import { X } from 'swiper/modules'` → `modules:[X]` → `import 'swiper/css/x'` |
| Everything at once | `import Swiper from 'swiper/bundle'` + `import 'swiper/css/bundle'` |
| React | `import { Swiper, SwiperSlide } from 'swiper/react'` |
| Vue | `import { Swiper, SwiperSlide } from 'swiper/vue'` |
| Web component | `import { register } from 'swiper/element/bundle'; register()` |
| Build (prod) | `npm run build:prod` → `dist/` |
| Validate | `npm run validate` |
| Active index | `swiper.activeIndex` (`swiper.realIndex` in loop) |
| Navigate in code | `slideNext()` / `slidePrev()` / `slideTo(i)` / `slideToLoop(i)` |
| Recalculate | `swiper.update()` or `observer:true` |
| Tear down | `swiper.destroy()` |

---

_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._
