# Flick Cards Slider

> Draggable card stack you flick through with momentum thresholds — tactile product and feature carousels.

**Definition:** Flick Cards Slider is a sliders UI animation from collections.html. It is built with HTML, CSS, JavaScript, and GSAP, ships with a live preview, and is free to copy into personal and commercial projects.

## Facts
- Category: Sliders
- Stack: HTML, CSS, JavaScript, and GSAP
- Added: 2026-08-04
- Canonical page: https://html.bosconvertpro.com/collection/flick-cards-slider
- Full-page preview: https://html.bosconvertpro.com/collection/flick-cards-slider/full
- Live demo: https://html.bosconvertpro.com/demos/flick-cards-slider/index.html
- Markdown mirror: https://html.bosconvertpro.com/collection/flick-cards-slider/index.md
- License: https://html.bosconvertpro.com/terms

## How to use
1. Open https://html.bosconvertpro.com/collection/flick-cards-slider/full to preview the animation in full screen.
2. Copy index.html, styles.css, and script.js from the code tabs on https://html.bosconvertpro.com/collection/flick-cards-slider.
3. Paste the files into your project and adjust timing, easing, and content as needed.

## FAQ
### What is Flick Cards Slider?

Flick Cards Slider is a sliders UI animation from collections.html. Draggable card stack you flick through with momentum thresholds — tactile product and feature carousels.

### What is Flick Cards Slider built with?

Flick Cards Slider is built with HTML, CSS, JavaScript, and GSAP. The source for every file is shown on the animation page and can be copied straight into your project.

### How do I use Flick Cards Slider in my project?

Open the animation page (https://html.bosconvertpro.com/collection/flick-cards-slider), preview it live, then copy index.html, styles.css, and script.js from the code tabs. Paste the files into your project and adjust timing, easing, and content as needed. A standalone demo runs at https://html.bosconvertpro.com/demos/flick-cards-slider/index.html.

### Is Flick Cards Slider free to use?

Yes. The Flick Cards Slider demo code may be used in personal and commercial projects. You may not resell or redistribute the collection itself as a competing template pack. Full terms: https://html.bosconvertpro.com/terms.

## Source — index.html
````html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Flick Cards Slider</title>
    <link rel="preconnect" href="https://fonts.googleapis.com" />
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
    <link rel="preconnect" href="https://images.unsplash.com" />
    <link
      href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap"
      rel="stylesheet"
    />
    <link rel="stylesheet" href="styles.css" />
  </head>
  <body>
    <main class="page">
      <div data-flick-cards-init class="flick-group">
        <div class="flick-group__relative-object">
          <div class="flick-group__relative-object-before"></div>
        </div>
        <div data-flick-cards-collection class="flick-group__collection">
          <div data-flick-cards-list class="flick-group__list">
            <div data-flick-cards-item-status data-flick-cards-item class="flick-group__item">
              <div class="flick-card">
                <div class="flick-card__before"></div>
                <div class="flick-card__media">
                  <img
                    width="640"
                    loading="eager"
                    alt="FX100"
                    src="https://images.unsplash.com/photo-1516035069371-29a1b244cc32?auto=format&fit=crop&w=900&q=85"
                    class="cover-image"
                    draggable="false"
                  />
                  <a href="#" class="flick-card__btn"
                    ><span class="flick-card__btn-span">Get this product</span></a
                  >
                  <h3 class="flick-card__h3">FX100</h3>
                </div>
              </div>
            </div>

            <div data-flick-cards-item-status data-flick-cards-item class="flick-group__item">
              <div class="flick-card">
                <div class="flick-card__before"></div>
                <div class="flick-card__media">
                  <img
                    width="640"
                    loading="lazy"
                    alt="LX200"
                    src="https://images.unsplash.com/photo-1526170375885-4d8ecf77b99f?auto=format&fit=crop&w=900&q=85"
                    class="cover-image"
                    draggable="false"
                  />
                  <a href="#" class="flick-card__btn"
                    ><span class="flick-card__btn-span">Get this product</span></a
                  >
                  <h3 class="flick-card__h3">LX200</h3>
                </div>
              </div>
            </div>

            <div data-flick-cards-item-status data-flick-cards-item class="flick-group__item">
              <div class="flick-card">
                <div class="flick-card__before"></div>
                <div class="flick-card__media">
                  <img
                    width="640"
                    loading="lazy"
                    alt="TX5"
                    src="https://images.unsplash.com/photo-1505740420928-5e560c06d30e?auto=format&fit=crop&w=900&q=85"
                    class="cover-image"
                    draggable="false"
                  />
                  <a href="#" class="flick-card__btn"
                    ><span class="flick-card__btn-span">Get this product</span></a
                  >
                  <h3 class="flick-card__h3">TX5</h3>
                </div>
              </div>
            </div>

            <div data-flick-cards-item-status data-flick-cards-item class="flick-group__item">
              <div class="flick-card">
                <div class="flick-card__before"></div>
                <div class="flick-card__media">
                  <img
                    width="640"
                    loading="lazy"
                    alt="NX400"
                    src="https://images.unsplash.com/photo-1542291026-7eec264c27ff?auto=format&fit=crop&w=900&q=85"
                    class="cover-image"
                    draggable="false"
                  />
                  <a href="#" class="flick-card__btn"
                    ><span class="flick-card__btn-span">Get this product</span></a
                  >
                  <h3 class="flick-card__h3">NX400</h3>
                </div>
              </div>
            </div>

            <div data-flick-cards-item-status data-flick-cards-item class="flick-group__item">
              <div class="flick-card">
                <div class="flick-card__before"></div>
                <div class="flick-card__media">
                  <img
                    width="640"
                    loading="lazy"
                    alt="TX9"
                    src="https://images.unsplash.com/photo-1572635196237-14b3f281503f?auto=format&fit=crop&w=900&q=85"
                    class="cover-image"
                    draggable="false"
                  />
                  <a href="#" class="flick-card__btn"
                    ><span class="flick-card__btn-span">Get this product</span></a
                  >
                  <h3 class="flick-card__h3">TX9</h3>
                </div>
              </div>
            </div>

            <div data-flick-cards-item-status data-flick-cards-item class="flick-group__item">
              <div class="flick-card">
                <div class="flick-card__before"></div>
                <div class="flick-card__media">
                  <img
                    width="640"
                    loading="lazy"
                    alt="RX300"
                    src="https://images.unsplash.com/photo-1491553895911-0055eca6402d?auto=format&fit=crop&w=900&q=85"
                    class="cover-image"
                    draggable="false"
                  />
                  <a href="#" class="flick-card__btn"
                    ><span class="flick-card__btn-span">Get this product</span></a
                  >
                  <h3 class="flick-card__h3">RX300</h3>
                </div>
              </div>
            </div>

            <div data-flick-cards-item-status data-flick-cards-item class="flick-group__item">
              <div class="flick-card">
                <div class="flick-card__before"></div>
                <div class="flick-card__media">
                  <img
                    width="640"
                    loading="lazy"
                    alt="KX120"
                    src="https://images.unsplash.com/photo-1523275335684-37898b6baf30?auto=format&fit=crop&w=900&q=85"
                    class="cover-image"
                    draggable="false"
                  />
                  <a href="#" class="flick-card__btn"
                    ><span class="flick-card__btn-span">Get this product</span></a
                  >
                  <h3 class="flick-card__h3">KX120</h3>
                </div>
              </div>
            </div>

            <div data-flick-cards-item-status data-flick-cards-item class="flick-group__item">
              <div class="flick-card">
                <div class="flick-card__before"></div>
                <div class="flick-card__media">
                  <img
                    width="640"
                    loading="lazy"
                    alt="MX60"
                    src="https://images.unsplash.com/photo-1484704849700-f032a568e944?auto=format&fit=crop&w=900&q=85"
                    class="cover-image"
                    draggable="false"
                  />
                  <a href="#" class="flick-card__btn"
                    ><span class="flick-card__btn-span">Get this product</span></a
                  >
                  <h3 class="flick-card__h3">MX60</h3>
                </div>
              </div>
            </div>

            <div data-flick-cards-item-status data-flick-cards-item class="flick-group__item">
              <div class="flick-card">
                <div class="flick-card__before"></div>
                <div class="flick-card__media">
                  <img
                    width="640"
                    loading="lazy"
                    alt="ZV210"
                    src="https://images.unsplash.com/photo-1606107557195-0e29a4b5b4aa?auto=format&fit=crop&w=900&q=85"
                    class="cover-image"
                    draggable="false"
                  />
                  <a href="#" class="flick-card__btn"
                    ><span class="flick-card__btn-span">Get this product</span></a
                  >
                  <h3 class="flick-card__h3">ZV210</h3>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </main>

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

## Source — styles.css
````css
*,
*::before,
*::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

html {
  height: 100%;
  -webkit-text-size-adjust: 100%;
  font-size: clamp(11px, 0.7vw + 8px, 16px);
}

body {
  min-height: 100%;
  color: #1a1714;
  background-color: #f3efe8;
  background-image:
    radial-gradient(
      ellipse 100% 80% at 12% 10%,
      rgba(255, 252, 247, 0.95) 0%,
      transparent 55%
    ),
    radial-gradient(
      ellipse 80% 70% at 88% 90%,
      rgba(232, 222, 208, 0.75) 0%,
      transparent 52%
    ),
    radial-gradient(
      ellipse 60% 50% at 50% 45%,
      rgba(245, 238, 228, 0.6) 0%,
      transparent 60%
    ),
    linear-gradient(
      160deg,
      #faf7f2 0%,
      #f3efe8 32%,
      #ebe4da 62%,
      #e4dcd0 100%
    );
  background-attachment: fixed;
  font-family: "Inter", system-ui, -apple-system, BlinkMacSystemFont, sans-serif;
  font-weight: 400;
  line-height: 1.25;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow: hidden;
}

img {
  display: block;
  max-width: 100%;
  border: 0;
  -webkit-user-drag: none;
  user-select: none;
}

a {
  color: inherit;
  text-decoration: none;
}

.page {
  min-height: 100vh;
  min-height: 100dvh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 2em 1.25em;
  overflow: hidden;
}

.flick-group {
  position: relative;
}

.flick-group__relative-object {
  opacity: 0;
  pointer-events: none;
  width: 47em;
  max-width: min(47em, 92vw);
  position: relative;
}

.flick-group__relative-object-before {
  padding-top: 75%;
}

.flick-group__collection {
  width: 100%;
  height: 100%;
  position: absolute;
  top: 0;
  left: 0;
}

.flick-group__list {
  justify-content: center;
  align-items: center;
  width: 100%;
  height: 100%;
  display: flex;
  position: relative;
}

.flick-group__item {
  position: absolute;
  will-change: transform, opacity;
}

.flick-card {
  color: #fff;
  -webkit-user-select: none;
  user-select: none;
  background-color: #000;
  border-radius: 1em;
  justify-content: center;
  align-items: center;
  width: 23.5em;
  max-width: min(23.5em, 58vw);
  display: flex;
  position: relative;
  overflow: hidden;
  box-shadow:
    0 1px 0 rgba(255, 255, 255, 0.08) inset,
    0 12px 40px rgba(26, 23, 20, 0.14),
    0 28px 64px rgba(26, 23, 20, 0.1);
}

.flick-card__before {
  padding-top: 150%;
}

.flick-card__media {
  justify-content: center;
  align-items: center;
  width: 100%;
  height: 100%;
  display: flex;
  position: absolute;
  top: 0;
  left: 0;
}

.cover-image {
  pointer-events: none;
  object-fit: cover;
  -webkit-user-select: none;
  user-select: none;
  width: 100%;
  height: 100%;
  position: absolute;
  top: 0;
  left: auto;
}

.flick-card__h3 {
  letter-spacing: -0.025em;
  font-size: 4em;
  font-weight: 500;
  line-height: 1;
  position: absolute;
  text-shadow: 0 2px 24px rgba(0, 0, 0, 0.35);
  z-index: 2;
}

.flick-card__btn {
  background-color: #000;
  border-radius: 0.375em;
  justify-content: center;
  align-items: center;
  width: calc(100% - 4em);
  height: 3.25em;
  text-decoration: none;
  display: flex;
  position: absolute;
  bottom: 2em;
  left: 2em;
  z-index: 2;
}

.flick-card__btn-span {
  color: #fff;
  font-size: 1em;
  font-weight: 500;
}

[data-flick-cards-dragger] {
  position: absolute;
  inset: 0;
  z-index: 3;
  pointer-events: auto;
  touch-action: pan-y;
}

[data-flick-drag-status="grab"] {
  cursor: grab;
}

[data-flick-drag-status="grabbing"] {
  cursor: grabbing;
}

[data-flick-drag-status="grabbing"] [data-flick-cards-dragger] {
  cursor: grabbing;
}

[data-flick-cards-item-status] .flick-card__media {
  transition: opacity 0.2s ease;
  opacity: 0.5;
}

[data-flick-cards-item-status="2-before"] .flick-card__media,
[data-flick-cards-item-status="2-after"] .flick-card__media {
  transition: opacity 0.2s ease;
  opacity: 0.75;
}

[data-flick-cards-item-status="active"] .flick-card__media {
  opacity: 1;
}

[data-flick-cards-item-status] .flick-card__btn {
  transition:
    opacity 0.4s cubic-bezier(0.625, 0.05, 0, 1),
    transform 1s cubic-bezier(0.16, 1, 0.3, 1);
  opacity: 0;
  transform: translate(0%, 50%) rotate(0.001deg);
  pointer-events: none;
}

[data-flick-cards-item-status="active"] .flick-card__btn {
  opacity: 1;
  transform: translate(0%, 0%) rotate(0.001deg);
  pointer-events: auto;
}

@media (max-width: 560px) {
  .flick-card__h3 {
    font-size: 3.25em;
  }

  .flick-card__btn {
    width: calc(100% - 2.5em);
    height: 2.85em;
    bottom: 1.25em;
    left: 1.25em;
  }
}
````

## Source — script.js
````javascript
gsap.registerPlugin(Draggable);

function initFlickCards() {
  const sliders = document.querySelectorAll("[data-flick-cards-init]");

  sliders.forEach((slider) => {
    const list = slider.querySelector("[data-flick-cards-list]");
    const cards = Array.from(list.querySelectorAll("[data-flick-cards-item]"));
    const total = cards.length;
    let activeIndex = 0;
    let sliderWidth = slider.offsetWidth;
    const threshold = 0.1;

    const draggers = [];
    cards.forEach((card) => {
      const dragger = document.createElement("div");
      dragger.setAttribute("data-flick-cards-dragger", "");
      card.appendChild(dragger);
      draggers.push(dragger);
    });

    slider.setAttribute("data-flick-drag-status", "grab");

    function getConfig(i, currentIndex) {
      let diff = i - currentIndex;
      if (diff > total / 2) diff -= total;
      else if (diff < -total / 2) diff += total;

      switch (diff) {
        case 0:
          return { x: 0, y: 0, rot: 0, s: 1, o: 1, z: 5 };
        case 1:
          return { x: 25, y: 1, rot: 10, s: 0.9, o: 1, z: 4 };
        case -1:
          return { x: -25, y: 1, rot: -10, s: 0.9, o: 1, z: 4 };
        case 2:
          return { x: 45, y: 5, rot: 15, s: 0.8, o: 1, z: 3 };
        case -2:
          return { x: -45, y: 5, rot: -15, s: 0.8, o: 1, z: 3 };
        default: {
          const dir = diff > 0 ? 1 : -1;
          return { x: 55 * dir, y: 5, rot: 20 * dir, s: 0.6, o: 0, z: 2 };
        }
      }
    }

    function renderCards(currentIndex) {
      cards.forEach((card, i) => {
        const cfg = getConfig(i, currentIndex);
        let status;

        if (cfg.x === 0) status = "active";
        else if (cfg.x === 25) status = "2-after";
        else if (cfg.x === -25) status = "2-before";
        else if (cfg.x === 45) status = "3-after";
        else if (cfg.x === -45) status = "3-before";
        else status = "hidden";

        card.setAttribute("data-flick-cards-item-status", status);
        card.style.zIndex = cfg.z;

        gsap.to(card, {
          duration: 0.6,
          ease: "elastic.out(1.2, 1)",
          xPercent: cfg.x,
          yPercent: cfg.y,
          rotation: cfg.rot,
          scale: cfg.s,
          opacity: cfg.o,
        });
      });
    }

    renderCards(activeIndex);

    if (total < 7) {
      return;
    }

    let pressClientX = 0;
    let pressClientY = 0;

    const dragInstances = Draggable.create(draggers, {
      type: "x",
      edgeResistance: 0.8,
      bounds: { minX: -sliderWidth / 2, maxX: sliderWidth / 2 },
      inertia: false,
      onPress() {
        sliderWidth = slider.offsetWidth;
        this.applyBounds({ minX: -sliderWidth / 2, maxX: sliderWidth / 2 });
        pressClientX = this.pointerEvent.clientX;
        pressClientY = this.pointerEvent.clientY;
        slider.setAttribute("data-flick-drag-status", "grabbing");
      },
      onDrag() {
        const rawProgress = this.x / sliderWidth;
        const progress = Math.min(1, Math.abs(rawProgress));
        const direction = rawProgress > 0 ? -1 : 1;
        const nextIndex = (activeIndex + direction + total) % total;

        cards.forEach((card, i) => {
          const from = getConfig(i, activeIndex);
          const to = getConfig(i, nextIndex);
          const mix = (prop) => from[prop] + (to[prop] - from[prop]) * progress;

          gsap.set(card, {
            xPercent: mix("x"),
            yPercent: mix("y"),
            rotation: mix("rot"),
            scale: mix("s"),
            opacity: mix("o"),
          });
        });
      },
      onRelease() {
        slider.setAttribute("data-flick-drag-status", "grab");

        const releaseClientX = this.pointerEvent.clientX;
        const releaseClientY = this.pointerEvent.clientY;
        const dragDistance = Math.hypot(
          releaseClientX - pressClientX,
          releaseClientY - pressClientY
        );
        const raw = this.x / sliderWidth;
        let shift = 0;

        if (raw > threshold) shift = -1;
        else if (raw < -threshold) shift = 1;

        if (shift !== 0) {
          activeIndex = (activeIndex + shift + total) % total;
          renderCards(activeIndex);
        } else {
          renderCards(activeIndex);
        }

        gsap.to(this.target, {
          x: 0,
          duration: 0.3,
          ease: "power1.out",
        });

        if (dragDistance < 4) {
          this.target.style.pointerEvents = "none";
          requestAnimationFrame(() => {
            requestAnimationFrame(() => {
              const el = document.elementFromPoint(releaseClientX, releaseClientY);
              if (el) {
                const evt = new MouseEvent("click", {
                  view: window,
                  bubbles: true,
                  cancelable: true,
                });
                el.dispatchEvent(evt);
              }
              this.target.style.pointerEvents = "auto";
            });
          });
        }
      },
    });

    window.addEventListener("resize", () => {
      sliderWidth = slider.offsetWidth;
      dragInstances.forEach((instance) => {
        instance.applyBounds({ minX: -sliderWidth / 2, maxX: sliderWidth / 2 });
      });
    });
  });
}

document.addEventListener("DOMContentLoaded", () => {
  initFlickCards();
});
````
