Stacked Cards Section
Click here to see the live demo.
- Next.js
- Typescript
- GSAP
- ScrollTrigger Plugin
- useGSAP Plugin
- Tailwind CSS
components/stacked-cards-section.tsx
"use client";
import gsap from "gsap";
import ScrollTrigger from "gsap/ScrollTrigger";
import { useGSAP } from "@gsap/react";
import { useRef } from "react";
gsap.registerPlugin(useGSAP, ScrollTrigger);
const PROCESS_DATA = [
{
step: "1",
title: "Sketch Design",
},
{
step: "2",
title: "Design Development",
},
{
step: "3",
title: "Development Application",
},
{
step: "4",
title: "Interior Design",
},
{
step: "5",
title: "Building approval plans",
},
{
step: "6",
title: "Construction plans",
},
];
export function StackedCards() {
const containerRef = useRef<HTMLElement>(null);
useGSAP(
() => {
if (!containerRef.current) return;
const cards = containerRef.current.querySelectorAll(".card");
cards.forEach((card, index) => {
if (index >= PROCESS_DATA.length - 1) return;
const cardInner = card.querySelector(".card-inner");
gsap.fromTo(
cardInner,
{
y: "0%",
z: 0,
rotationX: 0,
opacity: 1,
},
{
y: "-5%",
z: -50,
rotationX: 15,
opacity: 0,
scrollTrigger: {
trigger: cards[index + 1],
start: "top 75%",
end: `bottom 60%`,
scrub: true,
pin: card,
pinSpacing: false,
},
},
);
});
},
{ scope: containerRef },
);
return (
<section ref={containerRef}>
<div className="relative">
<div className="h-[75svh] bg-background border-b">
<h1 className="text-9xl px-5 py-20 font-semibold">OUR PROCESS</h1>
</div>
{PROCESS_DATA.map((process) => (
<div
key={process.title}
className="card flex justify-center items-center transform-3d perspective-distant will-change-transform h-[75svh]"
>
<div className="card-inner relative w-full h-full bg-background origin-[50%_100%] will-change-transform overflow-hidden p-10 grid grid-cols-2">
<p className="text-9xl font-semibold">[{process.step}]</p>
<h2 className="text-6xl font-semibold tracking-tight uppercase">
{process.title}
</h2>
</div>
</div>
))}
<div className="bg-background h-svh flex justify-center items-center border-t">
<p className="text-8xl font-serif">Fin</p>
</div>
</div>
</section>
);
}