Does Swiper loop mode reconcile original slide count with pagination bullet indices?
0 reputation · 08 Nov 2021, 13:14 UTC
0 reputation · 08 Nov 2021, 13:14 UTC
Swiper's pagination component tracks slide navigation, but its interaction with loop mode introduces a discrepancy between the original slide array length and the effective number of slides in a cyclic layout. When loop is enabled, Swiper clones the first and last slides for continuity, yet the default pagination.renderBullet function references the original slide count, potentially misaligning bullet indices with real slide positions. If pagination.clickable is activated, clicking a bullet is intended to navigate to the corresponding real slide index, but the offset from cloned slides may cause the viewport to land on an unintended position or trigger an unexpected loop transition. The precise conditions under which bullet indices correspond to actual slide positions, and whether the component normalizes these indices internally, remain ambiguous in the current documentation.
What determines whether pagination bullet indices align with real slide positions when loop mode is active? Does the clickable pagination behavior consistently skip cloned duplicates regardless of the initial slide index? Which configuration or custom renderBullet implementation ensures accurate index mapping without requiring manual index adjustments?
35275 reputation · 08 Nov 2021, 15:14 UTC
Yes, Swiper's pagination bullets always correspond to the original slide count (realIndex 0..n-1), not the cloned DOM slides created by loop mode. The clickable pagination behavior consistently navigates to the correct real slide position using slideToLoop(realIndex) internally, regardless of the initial slide index or clone offset.
When loop: true is enabled, Swiper clones the first and last slides (default one each side, configurable via loopedSlides) to create seamless cyclic transitions. This creates a discrepancy between two index systems:
The pagination module operates exclusively on realIndex. The default renderBullet function receives the real index as its argument, and clickable bullets call slideToLoop(realIndex), which calculates the optimal target slide (including clone offset) for the shortest transition path.
Clicking a bullet never lands on a cloned duplicate as a final resting position unless that clone represents the optimal path for the transition (e.g., looping backward from slide 0 to the last slide). The component normalizes the target using realIndex, so bullet 0 always navigates to the first original slide (or its clone when looping backward), bullet 1 to the second, and so on. This mapping remains consistent regardless of the initial slide index or loopedSlides value.
No manual index adjustment is required for standard usage. To customize bullets with accurate indices:
renderBullet callback — the provided index parameter is already realIndexswiper.realIndex in event handlers (slideChange, slideChangeTransitionEnd) for dynamic updatesindex === activeIndex in custom render functions when loop is activeIf you manually call slideTo() instead of slideToLoop(), you must account for the clone offset yourself; slideToLoop() handles this automatically.
Confirm the behavior in your implementation:
swiper.realIndex and swiper.activeIndex while clicking bulletsrealIndex matches the bullet index (0..n-1) while activeIndex differs by the clone offsetconsole.log('realIndex:', swiper.realIndex, 'activeIndex:', swiper.activeIndex) in an on('slideChange') handler to trace transitionsIf you add or remove slides dynamically with loop enabled, call swiper.loopDestroy(), update slides, then swiper.loopCreate() or swiper.update() to keep realIndex and pagination in sync.
Are you using a custom renderBullet that references activeIndex or assumes the passed index matches the DOM position? This is the most common cause of misalignment.
Use comments to ask for clarification. Post a solution as an answer.
35,275 reputation · 08 Nov 2021, 14:21 UTC
Pagination bullets generally map to realIndex (0 to n-1) rather than the cloned DOM positions created by loop: true. However, the index passed to a custom renderBullet can differ from swiper.realIndex depending on the Swiper version and whether looped clones are included in the internal slide list. Before relying on clickable bullets to skip clones, log both arguments in renderBullet and compare them against swiper.activeIndex and swiper.realIndex on slideChange. If they diverge by the leading clone count, adjust the custom bullet index manually or use the default renderer.