Diagnosing Swiper's Stale Slide Grid After Dynamic DOM Changes
When Swiper shows blank gaps or wrong pagination after you add or remove slides, its internal slide grid is stale. This guide walks through ordered checks, loop-mode cleanup, and update/observer fixes.
28 Mar 2026, 17:09 UTC

After you append or remove a .swiper-slide element, Swiper may show blank gaps, pagination bullets that no longer match the visible slides, or duplicated content that breaks navigation. The slider is not broken; its internal geometry cache is stale. The useful takeaway is that Swiper computes slide widths and offsets once at initialization, so any structural DOM change requires an explicit update() or a controlled loop-mode rebuild.
Recognizable condition
You add slides dynamically—perhaps from an API response or a filter action—and Swiper renders one or more of these symptoms:
- Blank gaps where slides should appear, even though the DOM contains the new elements.
- Pagination bullets that show the old slide count, or bullets that navigate to the wrong positions.
- In loop mode, duplicated slides that persist after you remove the originals, leaving orphaned clones in the wrapper.
These symptoms share a single root: Swiper's internal slidesGrid array and slide offset calculations were computed at initialization and are now out of sync with the actual DOM children.
Cause and diagnostic table
Use this table to narrow the cause before changing code.
| Symptom | Likely cause | Quick check |
|---|---|---|
| Blank gaps or zero-width slides | Stale slidesGrid, or CSS display: none / visibility: hidden on slides | Compare swiper.slidesGrid.length with the number of .swiper-slide elements |
| Pagination count wrong | Internal slide list not refreshed after mutation | Inspect pagination bullets; they should equal the non-duplicate slide count |
| Duplicated slides in loop mode | Orphaned .swiper-slide-duplicate nodes left after removal | Search .swiper-wrapper for .swiper-slide-duplicate after removing originals |
| Broken navigation after removal | Loop duplicate set out of sync with originals | Disable loop and retest; if navigation works, the loop cache is stale |
Ordered checks
- Validate DOM hierarchy. Confirm the structure is
.swiper > .swiper-wrapper > .swiper-slide. Swiper expects a single wrapper between the container and the slides; missing or extra wrapper levels break geometry calculations. - Count duplicate slide classes. In loop mode, Swiper injects
.swiper-slide-duplicatenodes. If you removed original slides without cleaning up, these duplicates remain and inflate the slide count. - Disable loop and re-test. Temporarily set
loop: falseand reinitialize. If the layout corrects itself, the duplication logic is the culprit rather than a generic update failure. - Call
swiper.update()insiderequestAnimationFrame. This forces Swiper to recalculateslidesGrid, slide sizes, and pagination. Deferring by one frame avoids mid-transition visual jumps. - Enable
observerwithobserveParents: true. This tells Swiper to watch forchildListmutations on the.swiper-wrapperand its parents. It is a safety net, not a replacement for explicit updates. - Resize across breakpoints. After the slide set stabilizes, change the viewport width and confirm that slide widths recalculate without stale offsets or horizontal scroll gaps.
Fixes tied to findings
Stale geometry after append or removal
Call swiper.update() after the DOM mutation settles. If you are inside a transition, wait for the transitionEnd event or wrap the call in requestAnimationFrame to prevent visual jumps.
Loop-mode duplicates after structural edits
When loop: true is active, do not remove or insert slides directly. Swiper maintains a duplicate set for infinite scrolling; editing the DOM without informing it leaves orphaned nodes. Use the loop lifecycle methods around your mutation:
// Browser console or application code, after Swiper initialization
const swiper = new Swiper('.swiper', {
loop: true,
// other options
});
// Before removing a slide in loop mode:
swiper.loopDestroy(); // remove duplicate nodes cleanly
const target = document.querySelector('.swiper-slide[data-id="42"]');
if (target) target.remove(); // structural DOM change
swiper.loopFix(); // rebuild loop duplicates
swiper.update(); // recalculate slidesGrid and pagination
If your Swiper build does not expose loopFix(), reinitialize the instance after loopDestroy() and the DOM edit. Verify the result by checking that .swiper-slide-duplicate count matches the new original count.
CSS hiding slides
Rules such as display: none or visibility: hidden on .swiper-slide produce zero-width calculations. Swiper will render blank space even after a correct update(). Remove or scope those rules so active slides remain visible.
Framework integration timing
In React, Vue, or similar frameworks, mutate the slide list only after the component mounts and the Swiper instance exists. Destroy the instance before unmounting the component so stale references do not outlive the DOM.
Verification and limitations
To confirm a fix, compare swiper.slidesGrid.length with the number of non-duplicate .swiper-slide elements. The pagination bullet count should match the same number. Resize the viewport across breakpoints and verify that slide widths recalculate without stale offsets.
Limitations to keep in mind:
- The
observeroption may miss mutations inside shadow DOM or when slides are replaced rather than added or removed, so manualupdate()remains necessary. - Calling
update()mid-transition can cause visual jumps; defer withrequestAnimationFrameor wait fortransitionEnd. - Loop mode injects duplicate DOM nodes; removing original slides without
loopDestroy()leaves orphaned duplicates that break navigation and screen-reader semantics.
Escalation criteria
Escalate the issue when the ordered checks and fixes above do not resolve the symptoms:
- Version mismatch. Verify the Swiper major version and the framework wrapper compatibility. Method names and loop internals have changed across major releases.
- CSS conflicts. Check for container-query or flexbox rules on ancestor elements that override Swiper's inline width calculations.
- Minimal reproduction. Prepare a standalone page with the exact Swiper version, browser version, and the DOM mutation code. Remove application CSS and framework wrappers until the failure is isolated.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.