Skip to content
Template Empire
Browse components

Scroll Stacked Cards

A free stacked cards scroll animation for React with restrained depth and a complete static fallback.

The story, layer by layer

A product story that builds one clear layer at a time

Follow the route from first signal to lasting insight. Each chapter settles into place while the complete story stays readable.

  1. 01 · Find the signal

    Turn scattered feedback into one clear direction

    Bring customer notes, product evidence, and commercial context into a shared view. The strongest signal rises without hiding the detail behind it.

    01 / 04

  2. 02 · Shape the route

    Give every decision a visible next move

    Frame the opportunity, assign ownership, and connect each dependency before work begins. The route stays legible as the story gathers depth.

    02 / 04

  3. 03 · Move together

    Keep momentum visible across every handoff

    See what is moving, what needs attention, and where the next decision sits. Teams keep their own rhythm while sharing one dependable operating picture.

    03 / 04

  4. 04 · Close the loop

    Carry the evidence into what comes next

    Connect outcomes back to the original signal so each launch sharpens the next one. The full story remains present, ordered, and ready to revisit.

    04 / 04

Customise

88px
18px
0.035
1.2deg
0.4s
420px
28px

Code

<ScrollStackedCards
  title="A product story that builds layer by layer"
  description="Follow one readable route from signal to insight."
  cards={[
    {
      id: "signal",
      eyebrow: "01 · Find the signal",
      title: "Turn feedback into one clear direction",
      description:
        "Bring customer evidence into a shared view.",
      visual: <div aria-hidden="true">Signal map</div>,
    },
    {
      id: "shape",
      eyebrow: "02 · Shape the route",
      title: "Give every decision a visible next move",
      description:
        "Connect each dependency before work begins.",
      visual: <div aria-hidden="true">Workflow preview</div>,
    },
    {
      id: "learn",
      eyebrow: "03 · Close the loop",
      title: "Carry the evidence into what comes next",
      description:
        "Connect outcomes back to the original signal.",
      visual: <div aria-hidden="true">Outcome preview</div>,
    },
  ]}
/>

Scroll Stacked Cards is a free stacked cards scroll animation for React, Next.js, and Tailwind. Three to seven substantial story cards settle into a CSS-sticky stack while scoped GSAP ScrollTriggers add restrained scale, rotation, and opacity depth to the cards already covered.

The section keeps native scrolling, semantic order, and every card's complete copy intact. On mobile, with reduced motion, or without JavaScript, the ordered list becomes a normal static layout with no transforms, inert content, or extended scroll range.

Install

Add the @te registry to your components.json once:

{
  "registries": {
    "@te": "https://templateempire.io/r/{name}.json"
  }
}

Then install the component:

npx shadcn@latest add @te/scroll-stacked-cards

Usage

import { ScrollStackedCards } from "@/components/scroll-stacked-cards";

const cards = [
  {
    id: "signal",
    eyebrow: "01 · Find the signal",
    title: "Turn feedback into one clear direction",
    description: "Bring customer evidence into a shared view.",
    visual: <div aria-hidden="true">Signal map</div>,
  },
  {
    id: "shape",
    eyebrow: "02 · Shape the route",
    title: "Give every decision a visible next move",
    description: "Connect each dependency before work begins.",
    visual: <div aria-hidden="true">Workflow preview</div>,
  },
  {
    id: "learn",
    eyebrow: "03 · Close the loop",
    title: "Carry the evidence into what comes next",
    description: "Connect outcomes back to the original signal.",
    visual: <div aria-hidden="true">Outcome preview</div>,
  },
];

export default function Page() {
  return (
    <ScrollStackedCards
      title="A product story that builds layer by layer"
      description="Follow one readable route from signal to insight."
      cards={cards}
    />
  );
}

Props

PropTypeDefaultDescription
eyebrowstring"The story, layer by layer"Introductory label rendered above the section heading.
titlestringrequiredSection heading rendered as the component's single h2.
descriptionstringundefinedOptional supporting section copy.
cards{ id: string; eyebrow?: string; title: string; description: string; visual?: ReactNode }[]requiredThree to seven ordered story cards with stable ids, complete copy, and optional consumer-owned visuals.
stickyOffsetnumber88First-card desktop sticky offset in CSS pixels, clamped from 64 to 144.
overlapnumber18Per-card desktop sticky offset in CSS pixels, clamped from 8 to 32.
scaleFalloffnumber0.035Scale lost for each covered depth, clamped from 0 to 0.07.
rotationnumber1.2Alternating maximum rotation in degrees, clamped from 0 to 3.
scrubnumber0.4ScrollTrigger catch-up duration in seconds, clamped from 0.1 to 1.1.
cardMinHeightnumber420Card minimum height in CSS pixels, clamped from 320 to 620.
radiusnumber28Card corner radius in CSS pixels, clamped from 12 to 40.
classNamestringundefinedAdditional classes merged onto the section root.

Customisation

Scroll Stacked Cards exposes three Tier 3 colour tokens. --scroll-stack-surface controls each card, --scroll-stack-visual controls the visual well, and --scroll-stack-accent colours visual highlights. Geometry and motion are controlled through the numeric props in the playground:

:root {
  --scroll-stack-surface: var(--background);
  --scroll-stack-visual: var(--background);
  --scroll-stack-accent: var(--ring);
}

Frequently asked questions

Is Scroll Stacked Cards free for commercial use?
Yes. Scroll Stacked Cards is MIT licensed, so you can use it in personal and commercial projects without attribution.
How does the stacked cards scroll animation handle accessibility?
The section is a labelled ordered list with one heading and complete description per card. Native page scrolling is never intercepted. A covered card is removed from sequential focus only when it is substantially occluded, then restored as soon as the visitor scrolls back.
What happens on mobile or with reduced motion?
The sticky range, transforms, opacity changes, and inert state are disabled. Every card renders immediately as a normal static list in the same document order, and the no-JavaScript output remains equally complete.

Related components

Want the full page this belongs to?Template Empire builds complete Next.js templates with section-level storytelling and one coherent motion system.Explore Template Empire templates