SwipiDocumentation

Guides

Troubleshooting

The five layout rules that keep measuring reliable, and the symptoms you see when one of them is broken.

The five rules of a measured layout

The carousel derives everything from getBoundingClientRect(). These five rules are what keep those measurements meaningful — nearly every layout bug below is one of them broken.

  • Leave the track's width alone and never set it to fit-content. Its automatic width fills the viewport, and the negative margin widens it by exactly one gap — which is what lets the last slide reach the right edge.
  • Give slides flex-shrink: 0 — the 0 in flex: 0 0 ….
  • Space slides with padding-left plus a matching negative margin-left on the track, never a trailing padding-right.
  • Keep scale() off the viewport, the track and the slides. Scaling something inside a slide is fine.
  • Change the gap through spaceBetween rather than a media query.

Symptoms and causes

Every slide is the width of the viewport

A percentage flex-basis resolves against the track. If the track is sized by its own content, that is circular and the numbers stop meaning anything.

Track width
/* ✗ circular: the basis resolves against a track sized by its content */
.carousel__track {
  display: flex;
  width: fit-content;
}

/* ✓ let the track fill the viewport */
.carousel__track {
  display: flex;
  margin-left: -16px;
}

The slides are narrower than I asked for

Without flex-shrink: 0 flexbox squeezes the row into the viewport, and the carousel measures the squeezed result rather than your intention.

Shrinking
/* ✗ the slides are squeezed to fit the viewport */
.carousel__slide {
  flex-basis: calc(100% / 3);
}

/* ✓ they keep the width you set */
.carousel__slide {
  flex: 0 0 calc(100% / 3);
}

The loop drifts a little every lap

A trailing padding makes the last slide box different from the rest. The gap has to belong to every slide equally.

Spacing
/* ✗ the last slide ends up different from the rest */
.carousel__slide {
  padding-right: 16px;
}

/* ✓ every slide box measures the same */
.carousel__track {
  margin-left: -16px;
}

.carousel__slide {
  padding-left: 16px;
}

The gap changes at a breakpoint and nothing happens

Sizes are watched with a ResizeObserver, and a slide's box keeps the same width when only its padding changes. Drive the gap from spaceBetween instead — see Responsive.

slideWidth and spaceBetween do not size anything

They only write --swipi-slide-width and --swipi-slide-gap onto the track. If no rule of yours reads those properties, nothing on screen changes — the CSS variables page has the stylesheet that reads them.

The drag stops mid-gesture on mobile

The browser claimed the gesture for scrolling. Give the viewport touch-action: pan-y.

There are fewer dots than slides

That is the intended behaviour: the carousel stops once the remaining slides fit the viewport, so five half-width slides give four snaps. Render dots from snapCount and they always match.

Carousels that start hidden

Still stuck

The playground puts every option next to a live carousel and prints the markup and the CSS your settings need, which is usually the fastest way to tell a layout problem from an option problem.

@ Copyright 2026 Midstem. All rights reserved.

DocsMidstemGitHubLinkedin