Mastering Swiper’s Loop Mode: Clones, Real Index, and Pagination Pitfalls
When Swiper’s loop: true is enabled, the library clones slides and shifts indices. This article explains how the cloning works, how to read the realIndex, and why pagination and navigation need special handling.
21 Jun 2026, 09:36 UTC

Why Swiper Needs to Clone Slides for Loop Mode
Setting loop: true turns a normal carousel into a seamless, infinite loop. Swiper cannot simply wrap the array of slides; it must create a visual buffer so that the transition from the last slide to the first (or vice‑versa) feels continuous. The library achieves this by cloning the first N slides to the end and the last N slides to the beginning, where N equals slidesPerView (or slidesPerGroup if set). The cloned elements are inserted into the DOM and given a data-swiper-slide-index that points back to the original slide.
Because of these clones the activeIndex property no longer represents the position in the original dataset. Instead, it indexes the extended array that includes both real and cloned slides. Swiper exposes realIndex to retrieve the zero‑based index of the original slide. For analytics, API calls, or UI sync you should always use realIndex.
Concrete Example: Swiper 11 with 5 Slides, 3 Visible
const swiper = new Swiper('#mySwiper', {
slidesPerView: 3,
loop: true,
pagination: {
el: '.swiper-pagination',
clickable: true
},
navigation: {
nextEl: '.swiper-button-next',
prevEl: '.swiper-button-prev'
}
});
After initialization you’ll see 11 .swiper-slide elements in the DOM: 5 originals, 3 leading clones, and 3 trailing clones. The data-swiper-slide-index on the clones points to the original indices 0‑4. Swiper automatically sets the translate so that the first real slide (index 0) is centered within the viewport.
Index Mapping in Action
| activeIndex | realIndex | Slide in DOM |
|---|---|---|
| 3 | 0 | First real slide |
| 4 | 1 | Second real slide |
| 5 | 2 | Third real slide |
| 6 | 3 | Fourth real slide |
| 7 | 4 | Last real slide |
Notice that activeIndex starts at 3 because Swiper has shifted the viewport to the first real slide. As the user swipes forward, activeIndex increments, but realIndex stays in the 0‑4 range.
Pagination and Navigation Wiring
Swiper’s built‑in pagination automatically updates the active bullet when loop is enabled, provided you do not override renderBullet with a static index. If you need custom bullets, read swiper.realIndex inside the slideChange event:
swiper.on('slideChange', () => {
const idx = swiper.realIndex;
// update external UI using idx
});
Navigation buttons work out of the box because Swiper internally maps the next/prev logic across the cloned boundaries. However, when you call swiper.slideTo(index) programmatically, you must pass the realIndex and set runCallbacks to true so Swiper resolves the correct cloned position.
Choosing Between loop and rewind
From Swiper 9 onward, rewind: true offers a simpler alternative. It snaps from the last slide to the first without cloning, keeping activeIndex === realIndex at all times. Use rewind when a true infinite scroll illusion is not required and you want predictable indices. Use loop when the visual continuity of a continuous carousel is essential.
Virtual Slides + Loop: A Compatibility Caveat
Virtual rendering (e.g., virtual: { slides: [], renderSlide }) is incompatible with loop: true in Swiper 8‑11. Swiper cannot clone virtual slides because they are not yet in the DOM. If you need both features, implement a custom buffer: render a window of real slides plus one extra on each side, then manually reset the position with swiper.slideToLoop(realIndex) when the user nears the buffer edge.
Common Mistakes and How to Avoid Them
- Using
data-swiper-slide-indexfor business logic: This value refers to the cloned position. Always readswiper.realIndexorswiper.slides[swiper.realIndex]for original data. - Destroying and re‑initializing without clearing the container:
swiper.destroy(true, true)leaves cloned nodes in the DOM. Callcontainer.innerHTML = originalHTMLbefore re‑init. - Relying on
:nth-childCSS selectors: They match cloned slides too. Use[data-swiper-slide-index]or add a custom class to original slides during render. - Assuming
activeIndexequalsrealIndexin loop mode: They differ. UserealIndexfor any external state. - Using
loopedSlidesin Swiper 11: This parameter is deprecated. The clone count is now derived fromslidesPerView(orslidesPerGroup).
Practical Verification Checklist
- Inspect the DOM after init: you should see
originalSlides + 2 * slidesPerViewelements. - Log
swiper.activeIndexandswiper.realIndexon eachslideChangeevent;realIndexshould cycle 0‑(n‑1). - Call
swiper.slideToLoop(2)and confirm the carousel animates to the third original slide. - Switch to
rewind: trueand verifyactiveIndex === realIndexand no cloned slides exist.
Conclusion
Loop mode in Swiper is powerful but introduces a layer of abstraction between the visual slides and their underlying data. By understanding the cloning strategy, using realIndex, and wiring pagination or navigation to the correct indices, you can build robust, infinite carousels that behave predictably across all interactions.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.