Overlapping Slider

A horizontally draggable slider where background cards scale down and rotate as they overlap behind the active slide, with inertia, snap, and keyboard navigation built in.

sliderdraggablegsapinertiaoverlapcardskeyboardaccessibility

Setup β€” External Scripts

GSAP 3.13.0
html
<script src="https://cdn.jsdelivr.net/npm/gsap@3.13.0/dist/gsap.min.js"></script>
Draggable Plugin
html
<script src="https://cdn.jsdelivr.net/npm/gsap@3.13.0/dist/Draggable.min.js"></script>
InertiaPlugin
html
<script src="https://cdn.jsdelivr.net/npm/gsap@3.13.0/dist/InertiaPlugin.min.js"></script>

Code

index.html
html
<div data-overlap-slider-init="" class="overlapping-slider__wrap">
  <div data-overlap-slider-collection="" class="overlapping-slider__collection">
    <div data-overlap-slider-list="" class="overlapping-slider__list">
      <div data-overlap-slider-item="" class="overlapping-slider__item">
        <div class="demo-card">
          <h2 class="demo-card__h">"These meal prep boxes honestly changed my evenings. Everything comes chopped, seasoned and labeled, the recipes are easy to follow, and dinner is on the table in like 15 minutes. Love it. 😍"</h2>
          <div class="demo-card__bottom">
            <div class="demo__card-avatar"><svg xmlns="http://www.w3.org/2000/svg" width="100%" viewbox="0 0 28 28" fill="none" class="demo-card__avatar-icon">
                <path d="M13.9987 13.4168C16.576 13.4168 18.6654 11.3275 18.6654 8.75016C18.6654 6.17283 16.576 4.0835 13.9987 4.0835C11.4214 4.0835 9.33203 6.17283 9.33203 8.75016C9.33203 11.3275 11.4214 13.4168 13.9987 13.4168Z" stroke="currentColor" stroke-width="1.5"></path>
                <path d="M5.25 24.5002V20.6619C5.25 20.1315 5.46071 19.6228 5.83579 19.2477L7.87597 17.2075C8.41163 16.6719 9.20397 16.4848 9.92264 16.7244L13.3675 17.8727C13.7781 18.0095 14.2219 18.0095 14.6325 17.8727L18.0774 16.7244C18.796 16.4848 19.5884 16.6719 20.124 17.2075L22.1642 19.2477C22.5393 19.6228 22.75 20.1315 22.75 20.6619V24.5002" stroke="currentColor" stroke-width="1.5"></path>
              </svg>
            </div>
            <span class="demo-card__p">Nina Calder</span>
          </div>
        </div>
      </div>
      <div data-overlap-slider-item="" class="overlapping-slider__item">
        <div class="demo-card">
          <h2 class="demo-card__h">"I'm terrible at planning meals, but this box makes it foolproof. Fresh veggies, good proteins, and zero guesswork. I eat healthier now and barely ever order takeaway anymore."</h2>
          <div class="demo-card__bottom">
            <div class="demo__card-avatar"><svg xmlns="http://www.w3.org/2000/svg" width="100%" viewbox="0 0 28 28" fill="none" class="demo-card__avatar-icon">
                <path d="M13.9987 13.4168C16.576 13.4168 18.6654 11.3275 18.6654 8.75016C18.6654 6.17283 16.576 4.0835 13.9987 4.0835C11.4214 4.0835 9.33203 6.17283 9.33203 8.75016C9.33203 11.3275 11.4214 13.4168 13.9987 13.4168Z" stroke="currentColor" stroke-width="1.5"></path>
                <path d="M5.25 24.5002V20.6619C5.25 20.1315 5.46071 19.6228 5.83579 19.2477L7.87597 17.2075C8.41163 16.6719 9.20397 16.4848 9.92264 16.7244L13.3675 17.8727C13.7781 18.0095 14.2219 18.0095 14.6325 17.8727L18.0774 16.7244C18.796 16.4848 19.5884 16.6719 20.124 17.2075L22.1642 19.2477C22.5393 19.6228 22.75 20.1315 22.75 20.6619V24.5002" stroke="currentColor" stroke-width="1.5"></path>
              </svg>
            </div>
            <span class="demo-card__p">Marcus Roque</span>
          </div>
        </div>
      </div>
      <div data-overlap-slider-item="" class="overlapping-slider__item">
        <div class="demo-card">
          <h2 class="demo-card__h">"Portions are perfect and the flavors are way better than I expected from a subscription. I just open a bag, toss it in the pan and feel like a real cook without any stress."</h2>
          <div class="demo-card__bottom">
            <div class="demo__card-avatar"><svg xmlns="http://www.w3.org/2000/svg" width="100%" viewbox="0 0 28 28" fill="none" class="demo-card__avatar-icon">
                <path d="M13.9987 13.4168C16.576 13.4168 18.6654 11.3275 18.6654 8.75016C18.6654 6.17283 16.576 4.0835 13.9987 4.0835C11.4214 4.0835 9.33203 6.17283 9.33203 8.75016C9.33203 11.3275 11.4214 13.4168 13.9987 13.4168Z" stroke="currentColor" stroke-width="1.5"></path>
                <path d="M5.25 24.5002V20.6619C5.25 20.1315 5.46071 19.6228 5.83579 19.2477L7.87597 17.2075C8.41163 16.6719 9.20397 16.4848 9.92264 16.7244L13.3675 17.8727C13.7781 18.0095 14.2219 18.0095 14.6325 17.8727L18.0774 16.7244C18.796 16.4848 19.5884 16.6719 20.124 17.2075L22.1642 19.2477C22.5393 19.6228 22.75 20.1315 22.75 20.6619V24.5002" stroke="currentColor" stroke-width="1.5"></path>
              </svg>
            </div>
            <span class="demo-card__p">Elena Strauss</span>
          </div>
        </div>
      </div>
      <div data-overlap-slider-item="" class="overlapping-slider__item">
        <div class="demo-card">
          <h2 class="demo-card__h">"These boxes save me so much time after work. No grocery queues, no chopping mountains of vegetables, just quick instructions and tasty food that actually fits my diet."</h2>
          <div class="demo-card__bottom">
            <div class="demo__card-avatar"><svg xmlns="http://www.w3.org/2000/svg" width="100%" viewbox="0 0 28 28" fill="none" class="demo-card__avatar-icon">
                <path d="M13.9987 13.4168C16.576 13.4168 18.6654 11.3275 18.6654 8.75016C18.6654 6.17283 16.576 4.0835 13.9987 4.0835C11.4214 4.0835 9.33203 6.17283 9.33203 8.75016C9.33203 11.3275 11.4214 13.4168 13.9987 13.4168Z" stroke="currentColor" stroke-width="1.5"></path>
                <path d="M5.25 24.5002V20.6619C5.25 20.1315 5.46071 19.6228 5.83579 19.2477L7.87597 17.2075C8.41163 16.6719 9.20397 16.4848 9.92264 16.7244L13.3675 17.8727C13.7781 18.0095 14.2219 18.0095 14.6325 17.8727L18.0774 16.7244C18.796 16.4848 19.5884 16.6719 20.124 17.2075L22.1642 19.2477C22.5393 19.6228 22.75 20.1315 22.75 20.6619V24.5002" stroke="currentColor" stroke-width="1.5"></path>
              </svg>
            </div>
            <span class="demo-card__p">Jared Kimani</span>
          </div>
        </div>
      </div>
      <div data-overlap-slider-item="" class="overlapping-slider__item">
        <div class="demo-card">
          <h2 class="demo-card__h">"I love how the meals are balanced without feeling like 'diet food'. Sauces are delicious, ingredients stay super fresh, and cleanup is basically one pan and a plate. πŸ™Œ"</h2>
          <div class="demo-card__bottom">
            <div class="demo__card-avatar"><svg xmlns="http://www.w3.org/2000/svg" width="100%" viewbox="0 0 28 28" fill="none" class="demo-card__avatar-icon">
                <path d="M13.9987 13.4168C16.576 13.4168 18.6654 11.3275 18.6654 8.75016C18.6654 6.17283 16.576 4.0835 13.9987 4.0835C11.4214 4.0835 9.33203 6.17283 9.33203 8.75016C9.33203 11.3275 11.4214 13.4168 13.9987 13.4168Z" stroke="currentColor" stroke-width="1.5"></path>
                <path d="M5.25 24.5002V20.6619C5.25 20.1315 5.46071 19.6228 5.83579 19.2477L7.87597 17.2075C8.41163 16.6719 9.20397 16.4848 9.92264 16.7244L13.3675 17.8727C13.7781 18.0095 14.2219 18.0095 14.6325 17.8727L18.0774 16.7244C18.796 16.4848 19.5884 16.6719 20.124 17.2075L22.1642 19.2477C22.5393 19.6228 22.75 20.1315 22.75 20.6619V24.5002" stroke="currentColor" stroke-width="1.5"></path>
              </svg>
            </div>
            <span class="demo-card__p">Priya Desai</span>
          </div>
        </div>
      </div>
      <div data-overlap-slider-item="" class="overlapping-slider__item">
        <div class="demo-card">
          <h2 class="demo-card__h">"The variety surprises me every week. I've tried dishes I'd never think to make myself, but everything is simple enough that I can cook while half-asleep and still nail it."</h2>
          <div class="demo-card__bottom">
            <div class="demo__card-avatar"><svg xmlns="http://www.w3.org/2000/svg" width="100%" viewbox="0 0 28 28" fill="none" class="demo-card__avatar-icon">
                <path d="M13.9987 13.4168C16.576 13.4168 18.6654 11.3275 18.6654 8.75016C18.6654 6.17283 16.576 4.0835 13.9987 4.0835C11.4214 4.0835 9.33203 6.17283 9.33203 8.75016C9.33203 11.3275 11.4214 13.4168 13.9987 13.4168Z" stroke="currentColor" stroke-width="1.5"></path>
                <path d="M5.25 24.5002V20.6619C5.25 20.1315 5.46071 19.6228 5.83579 19.2477L7.87597 17.2075C8.41163 16.6719 9.20397 16.4848 9.92264 16.7244L13.3675 17.8727C13.7781 18.0095 14.2219 18.0095 14.6325 17.8727L18.0774 16.7244C18.796 16.4848 19.5884 16.6719 20.124 17.2075L22.1642 19.2477C22.5393 19.6228 22.75 20.1315 22.75 20.6619V24.5002" stroke="currentColor" stroke-width="1.5"></path>
              </svg>
            </div>
            <span class="demo-card__p">TomΓ‘s Herrera</span>
          </div>
        </div>
      </div>
      <div data-overlap-slider-item="" class="overlapping-slider__item">
        <div class="demo-card">
          <h2 class="demo-card__h">"These meal prep kits made lunches at work a lot less boring. I cook two portions at night, pack one for tomorrow, and I'm done. No more sad sandwiches or vending machines."</h2>
          <div class="demo-card__bottom">
            <div class="demo__card-avatar"><svg xmlns="http://www.w3.org/2000/svg" width="100%" viewbox="0 0 28 28" fill="none" class="demo-card__avatar-icon">
                <path d="M13.9987 13.4168C16.576 13.4168 18.6654 11.3275 18.6654 8.75016C18.6654 6.17283 16.576 4.0835 13.9987 4.0835C11.4214 4.0835 9.33203 6.17283 9.33203 8.75016C9.33203 11.3275 11.4214 13.4168 13.9987 13.4168Z" stroke="currentColor" stroke-width="1.5"></path>
                <path d="M5.25 24.5002V20.6619C5.25 20.1315 5.46071 19.6228 5.83579 19.2477L7.87597 17.2075C8.41163 16.6719 9.20397 16.4848 9.92264 16.7244L13.3675 17.8727C13.7781 18.0095 14.2219 18.0095 14.6325 17.8727L18.0774 16.7244C18.796 16.4848 19.5884 16.6719 20.124 17.2075L22.1642 19.2477C22.5393 19.6228 22.75 20.1315 22.75 20.6619V24.5002" stroke="currentColor" stroke-width="1.5"></path>
              </svg>
            </div>
            <span class="demo-card__p">Leah Morrison</span>
          </div>
        </div>
      </div>
      <div data-overlap-slider-item="" class="overlapping-slider__item">
        <div class="demo-card">
          <h2 class="demo-card__h">"I started this to stop wasting groceries and it worked. Everything is pre-measured, there's almost no trash, and my fridge finally looks organized instead of chaotic."</h2>
          <div class="demo-card__bottom">
            <div class="demo__card-avatar"><svg xmlns="http://www.w3.org/2000/svg" width="100%" viewbox="0 0 28 28" fill="none" class="demo-card__avatar-icon">
                <path d="M13.9987 13.4168C16.576 13.4168 18.6654 11.3275 18.6654 8.75016C18.6654 6.17283 16.576 4.0835 13.9987 4.0835C11.4214 4.0835 9.33203 6.17283 9.33203 8.75016C9.33203 11.3275 11.4214 13.4168 13.9987 13.4168Z" stroke="currentColor" stroke-width="1.5"></path>
                <path d="M5.25 24.5002V20.6619C5.25 20.1315 5.46071 19.6228 5.83579 19.2477L7.87597 17.2075C8.41163 16.6719 9.20397 16.4848 9.92264 16.7244L13.3675 17.8727C13.7781 18.0095 14.2219 18.0095 14.6325 17.8727L18.0774 16.7244C18.796 16.4848 19.5884 16.6719 20.124 17.2075L22.1642 19.2477C22.5393 19.6228 22.75 20.1315 22.75 20.6619V24.5002" stroke="currentColor" stroke-width="1.5"></path>
              </svg>
            </div>
            <span class="demo-card__p">Caleb Wright</span>
          </div>
        </div>
      </div>
      <div data-overlap-slider-item="" class="overlapping-slider__item">
        <div class="demo-card">
          <h2 class="demo-card__h">"The step-by-step cards are super clear, even for someone who usually burns toast. I feel confident in the kitchen now, and my friends keep asking for the recipes. πŸ˜…"</h2>
          <div class="demo-card__bottom">
            <div class="demo__card-avatar"><svg xmlns="http://www.w3.org/2000/svg" width="100%" viewbox="0 0 28 28" fill="none" class="demo-card__avatar-icon">
                <path d="M13.9987 13.4168C16.576 13.4168 18.6654 11.3275 18.6654 8.75016C18.6654 6.17283 16.576 4.0835 13.9987 4.0835C11.4214 4.0835 9.33203 6.17283 9.33203 8.75016C9.33203 11.3275 11.4214 13.4168 13.9987 13.4168Z" stroke="currentColor" stroke-width="1.5"></path>
                <path d="M5.25 24.5002V20.6619C5.25 20.1315 5.46071 19.6228 5.83579 19.2477L7.87597 17.2075C8.41163 16.6719 9.20397 16.4848 9.92264 16.7244L13.3675 17.8727C13.7781 18.0095 14.2219 18.0095 14.6325 17.8727L18.0774 16.7244C18.796 16.4848 19.5884 16.6719 20.124 17.2075L22.1642 19.2477C22.5393 19.6228 22.75 20.1315 22.75 20.6619V24.5002" stroke="currentColor" stroke-width="1.5"></path>
              </svg>
            </div>
            <span class="demo-card__p">Sophie Lang</span>
          </div>
        </div>
      </div>
      <div data-overlap-slider-item="" class="overlapping-slider__item">
        <div class="demo-card">
          <h2 class="demo-card__h">"Honestly the best habit I've picked up all year. These boxes keep me cooking at home, eating real food, and still give me my evenings back. Feels like cheating at adulting."</h2>
          <div class="demo-card__bottom">
            <div class="demo__card-avatar"><svg xmlns="http://www.w3.org/2000/svg" width="100%" viewbox="0 0 28 28" fill="none" class="demo-card__avatar-icon">
                <path d="M13.9987 13.4168C16.576 13.4168 18.6654 11.3275 18.6654 8.75016C18.6654 6.17283 16.576 4.0835 13.9987 4.0835C11.4214 4.0835 9.33203 6.17283 9.33203 8.75016C9.33203 11.3275 11.4214 13.4168 13.9987 13.4168Z" stroke="currentColor" stroke-width="1.5"></path>
                <path d="M5.25 24.5002V20.6619C5.25 20.1315 5.46071 19.6228 5.83579 19.2477L7.87597 17.2075C8.41163 16.6719 9.20397 16.4848 9.92264 16.7244L13.3675 17.8727C13.7781 18.0095 14.2219 18.0095 14.6325 17.8727L18.0774 16.7244C18.796 16.4848 19.5884 16.6719 20.124 17.2075L22.1642 19.2477C22.5393 19.6228 22.75 20.1315 22.75 20.6619V24.5002" stroke="currentColor" stroke-width="1.5"></path>
              </svg>
            </div>
            <span class="demo-card__p">Dylan Kozlov</span>
          </div>
        </div>
      </div>
    </div>
  </div>
</div>
styles.css
css
.overlapping-slider__wrap {
  width: 100%;
}

.overlapping-slider__collection {
  justify-content: flex-start;
  align-items: flex-start;
  width: 100%;
  display: flex;
  position: relative;
}

.overlapping-slider__list {
  flex-flow: row;
  flex: none;
  justify-content: flex-start;
  align-items: center;
  display: flex;
  position: relative;
}

.overlapping-slider__item {
  flex: none;
  margin-right: 1.5em;
}

.demo-card {
  grid-column-gap: 2em;
  grid-row-gap: 2em;
  aspect-ratio: 3 / 4;
  background-color: #fff;
  border: .1875em solid #000;
  border-radius: 1em;
  flex-flow: column;
  justify-content: space-between;
  align-items: flex-start;
  width: 24em;
  max-width: 85vw;
  padding: 3em 2em 2em;
  display: flex;
}

.demo-card__h {
  margin-top: 0;
  margin-bottom: 0;
  font-size: 1.5em;
  font-weight: 600;
  line-height: 1.3;
}

.demo-card__bottom {
  grid-column-gap: .75em;
  grid-row-gap: .75em;
  flex-flow: row;
  justify-content: flex-start;
  align-items: center;
  display: flex;
}

.demo__card-avatar {
  color: #fff;
  background-color: #ffce16;
  border-radius: 100em;
  flex: none;
  width: 3em;
  height: 3em;
  padding: .625em;
}

.demo-card__avatar-icon {
  width: 100%;
  height: 100%;
}

.demo-card__p {
  font-size: 1.25em;
  font-weight: 600;
  line-height: 1;
}
script.js
javascript
function initOverlappingSlider() {
  const inits = document.querySelectorAll('[data-overlap-slider-init]');
  if (!inits.length) return;

  inits.forEach(setupOverlappingSlider);

  function setupOverlappingSlider(init) {
    // --- attributes with defaults
    const minScale = +(init.getAttribute('data-scale')  ?? 0.45);
    const maxRotation = +(init.getAttribute('data-rotate') ?? -8);
    const inertia = true;

    const wrap = init.querySelector('[data-overlap-slider-collection]');
    const slider = init.querySelector('[data-overlap-slider-list]');
    const slides = Array.from(init.querySelectorAll('[data-overlap-slider-item]'));

    if (!wrap || !slider || !slides.length) {
      console.warn("OverlappingSlider: missing required structure. Check Osmo Vault documentation please.");
      return;
    }

    wrap.style.touchAction = 'none';
    wrap.style.userSelect = 'none';

    let spacing = 0;
    let slideW = 0;
    let maxDrag = 0;
    let dragX = 0;
    let draggable;

    // simple clamp that always uses latest maxDrag
    function clamp(value) {
      if (maxDrag <= 0) return 0;
      return Math.min(Math.max(value, 0), maxDrag);
    }

    function update() {
      // move the whole list
      gsap.set(slider, { x: -dragX });

      // update each slide's overlap transform
      slides.forEach((slide, i) => {
        const threshold = i * spacing;
        const local = Math.max(0, dragX - threshold);
        const t = spacing > 0 ? Math.min(local / spacing, 1) : 0;

        gsap.set(slide, {
          x: local,
          scale: 1 - (1 - minScale) * t,
          rotation: maxRotation * t,
          transformOrigin: '75% center'
        });
      });
    }

    function recalc() {
      if (!slides.length) return;

      // measure one slide to get width + margin-right as "gap"
      const style = getComputedStyle(slides[0]);
      const gapRight = parseFloat(style.marginRight) || 0;

      slideW = slides[0].offsetWidth;
      spacing = slideW + gapRight;
      maxDrag = spacing * (slides.length - 1);

      // keep dragX within new bounds
      dragX = clamp(dragX);
      update();

      if (draggable) {
        draggable.applyBounds({ minX: -maxDrag, maxX: 0 });
      }
    }

    // create draggable
    draggable = Draggable.create(slider, {
      type: 'x',
      bounds: { minX: -maxDrag, maxX: 0 }, // will be updated after recalc
      inertia,
      maxDuration: 1,
      snap: true
        ? (raw) => {
            // raw is the x value
            const d = clamp(-raw);
            const idx = spacing > 0 ? Math.round(d / spacing) : 0;
            return -idx * spacing;
          }
        : false,
      onDrag() {
        dragX = clamp(-this.x);
        update();
      },
      onThrowUpdate() {
        dragX = clamp(-this.x);
        update();
      }
    })[0];

    // recalc on resize
    const ro = new ResizeObserver(() => {
      recalc();
    });
    ro.observe(init);

    // keyboard navigation (arrow left/right)
    let active = false;
    let currentIndex = 0;

    // helper function to switch slides
    function goToSlide(idx) {
      idx = Math.max(0, Math.min(idx, slides.length - 1));
      currentIndex = idx;

      const targetX = idx * spacing;

      gsap.to({ value: dragX }, {
        value: targetX,
        duration: 0.35,
        ease: "power4.out",
        onUpdate: function () {
          dragX = this.targets()[0].value;
          gsap.set(slider, { x: -dragX });
          update(); // animate overlap transforms properly
        }
      });

      wrap.setAttribute("aria-label", `Slide ${idx + 1} of ${slides.length}`);
    }

    // Observe visibility
    const io = new IntersectionObserver(entries => {
      active = entries[0].isIntersecting;
    }, {
      threshold: 0.25 // slider must be at least 25% visible
    });

    io.observe(init);

    // Aria labels for accessibility
    wrap.setAttribute("role", "region");
    wrap.setAttribute("aria-roledescription", "carousel");
    wrap.setAttribute("aria-label", "Testimonial slider");

    // key listener
    function onKey(e) {
      if (!active) return; // only respond when slider in view

      if (e.key === "ArrowLeft") {
        e.preventDefault();
        goToSlide(currentIndex - 1);
      }

      if (e.key === "ArrowRight") {
        e.preventDefault();
        goToSlide(currentIndex + 1);
      }
    }
    window.addEventListener("keydown", onKey);

    // initial layout
    recalc();
  }
}

// Initialize Overlapping Slider
document.addEventListener("DOMContentLoaded", function () {
  initOverlappingSlider();
});

Attributes

NameTypeDefaultDescription
data-overlap-slider-initstring""Add to the outermost wrapper to activate the Overlapping Slider instance. All measurements, Draggable setup, and keyboard listeners are scoped to this element.
data-overlap-slider-collectionstring""Add to the outer container that receives ARIA roles, visibility tracking via IntersectionObserver, and keyboard-driven slide announcements.
data-overlap-slider-liststring""Add to the horizontally draggable list element that GSAP positions using drag values and inertia. Must be a direct parent of all slide items.
data-overlap-slider-itemstring""Add to each individual slide card to register it in the overlapping transform logic. Each item receives independent scale, rotation, and x transforms based on drag position.
data-scalenumber0.45Sets the minimum scale applied to background cards as they overlap behind the active slide. Lower values create more dramatic depth.
data-rotatenumber-8Defines how many degrees each background card tilts while transitioning. Negative values tilt counter-clockwise.

Notes

  • β€’The gap between slides is read from margin-right on the first slide element, so always define inter-slide spacing via margin-right in CSS rather than gap or padding.
  • β€’The slider list must be set to flex: none so it keeps the combined width of all slides and does not shrink to the collection container.
  • β€’The snap function rounds the raw drag x value to the nearest slide index, ensuring the slider always lands cleanly on a card after inertia completes.
  • β€’A ResizeObserver recalculates slide width, spacing, and maxDrag on every container resize so the slider remains accurate after viewport changes.
  • β€’Keyboard navigation activates only when the slider is at least 25% visible in the viewport, preventing arrow keys from hijacking scroll when the slider is off-screen.
  • β€’ARIA attributes (role, aria-roledescription, aria-label) are applied programmatically to the collection element and updated on every keyboard-driven slide change.
  • β€’Keep the slides themselves minimal and place your styled card content inside each [data-overlap-slider-item] wrapper for easy reuse across different instances.

Guide

Init, Collection & List

Add [data-overlap-slider-init] to the outermost wrapper, [data-overlap-slider-collection] to the direct child that handles ARIA and visibility, and [data-overlap-slider-list] to the draggable list inside it. The list must be flex: none to retain the full combined width of all slides.

Slide items

Add [data-overlap-slider-item] to each card wrapper. Place your actual styled card element inside this wrapper β€” keeping the item itself unstyled makes it easy to reuse the slider with different card designs.

Spacing between slides

Set margin-right on .overlapping-slider__item in CSS to control the gap. The script reads this value via getComputedStyle to calculate spacing and snap points β€” do not use gap or padding on the list.

Scale & Rotation

Use data-scale (default 0.45) on the init element to set how small background cards shrink, and data-rotate (default -8) to control their tilt angle. Both values are interpolated per slide based on how far they are from the front.

Keyboard navigation

Arrow Left and Arrow Right keys step through slides when the component is at least 25% visible. The aria-label on the collection element is updated to announce the current slide index for screen readers.

Inertia & Snap

InertiaPlugin provides momentum after a drag release, and the snap function rounds to the nearest slide index so the slider always settles on a full card. Adjust maxDuration on the Draggable config to control how quickly inertia settles.