SwipiDocumentation

API

CSS variables

For a gap or a slide width that comes from state rather than from the viewport — the two custom properties the carousel writes onto the track, and when you can ignore them.

What this is for

One case, and it is worth stating before the mechanics: a gap or a slide width that comes from state rather than from the viewport. A density toggle, a user setting, a value from your design tokens — things a media query cannot express because they do not depend on the screen at all.

React
const [isCompact, setIsCompact] = useState(false)

const [carouselRef, carousel] = useSwipiCarousel({
  spaceBetween: isCompact ? 8 : 24
})

return (
  <>
    <button type="button" onClick={() => setIsCompact(!isCompact)}>
      {isCompact ? 'Comfortable' : 'Compact'}
    </button>

    <div className="carousel__viewport" ref={carouselRef}>
      {/* … */}
    </div>
  </>
)

Two things have to happen when that state flips: your CSS needs the new number, and the carousel needs to re-measure. The options do both — the number arrives as a custom property, and the change is a re-measure signal on its own.

What the options actually do

Exactly two things, and neither is sizing:

  • They write at most two custom properties onto the track element. The carousel never reads them back — the geometry still comes from measuring the DOM.
  • Changing either value re-measures the carousel before the next paint.
PropertyTypeDescription
--swipi-slide-widthpxWritten when slideWidth is passed, removed when it is not. Nothing reads it but your stylesheet.
--swipi-slide-gappxWritten when spaceBetween is passed, removed when it is not. Use it for both the slide's padding and the track's negative margin so the pair always agrees.
Rendered track
<div class="carousel__track" style="--swipi-slide-width: 300px; --swipi-slide-gap: 12px">

Reading them

Put the var() calls in the track and the slide rule, with a fallback for the case where the option is absent.

Stylesheet
.carousel__track {
  display: flex;
  margin-left: calc(-1 * var(--swipi-slide-gap, 0px));
}

.carousel__slide {
  box-sizing: border-box;
  flex: 0 0 calc(var(--swipi-slide-width, 300px) + var(--swipi-slide-gap, 0px));
  min-width: 0;
  padding-left: var(--swipi-slide-gap, 0px);
}
React
const [carouselRef] = useSwipiCarousel({
  slideWidth: 300,
  spaceBetween: 12
})

Now the options decide the width and the gap. Dropping an option takes the property back off the track, so the fallback in var() takes over rather than the layout collapsing.

In Tailwind

Arbitrary values read the same properties, so a Tailwind carousel can be driven by the options too.

Tailwind
<div className="flex ml-[calc(-1*var(--swipi-slide-gap,0px))]">
  <div className="min-w-0 shrink-0 grow-0 basis-[calc(var(--swipi-slide-width,300px)+var(--swipi-slide-gap,0px))] pl-[var(--swipi-slide-gap,0px)]">
    {item.title}
  </div>
</div>

When you do not need this

Most carousels never touch either option, and that is the intended shape of the API rather than a shortcut. Skip them when:

  • The gap is a constant. Write the number in the stylesheet. Passing it as an option adds a round trip and changes nothing on screen.
  • It only changes at breakpoints that also change the number of visible slides. The slide width changes with it, so the carousel re-measures on its own — a media query is enough.
  • Your CSS does not mention the properties. Then the options are inert as far as layout goes: they still trigger a re-measure, but nothing moves.
The usual case
/* nothing to pass to the carousel — this is the normal case */
.carousel__track {
  display: flex;
  margin-left: -24px;
}

.carousel__slide {
  box-sizing: border-box;
  flex: 0 0 calc(100% / 3);
  min-width: 0;
  padding-left: 24px;
}

@ Copyright 2026 Midstem. All rights reserved.

DocsMidstemGitHubLinkedin