Cascade Card Deck
A scroll-stacked feature list where each card is sticky at a stepped top offset, so scrolling pins them into an overlapping deck with the newest on top. Big stat numbers anchor every card, and the surface and badge colours are per-card props so the deck can stay monochrome or lean into an accent.
CardReactTailwind CSSSolar Icons
CSSTailwind
Manual
Create a file and paste the following code into it.
cascade-card-deck.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
"use client";
import { type IconProps } from "@solar-icons/react";
import { cn } from "@/lib/cn";
/** Solar exports only IconProps at the root; alias the component type. */
type Icon = import("react").ComponentType<IconProps>;
/* ------------------------------------------------------------------ */
/* CascadeCardDeck */
/* ------------------------------------------------------------------ */
export interface FeatureCard {
value: string;
title: string;
description: string;
icon: Icon;
/** Card surface classes [Optional, default: neutral] */
cardClassName?: string;
/** Icon badge classes [Optional, default: neutral] */
iconClassName?: string;
}
interface CascadeCardDeckProps {
cards: FeatureCard[];
className?: string;
}
/**
* A scroll-stacked feature list: each card is sticky at a stepped top offset,
* so scrolling pins them into an overlapping deck with the newest on top. Big
* stat numbers anchor each card, and the surface/badge colours are per-card
* props so the deck can stay monochrome or lean into an accent.
* @param {FeatureCard[]} cards - Cards, rendered top to bottom [Required]
*/
export function CascadeCardDeck({ cards, className }: CascadeCardDeckProps) {
return (
<ul className={cn("relative space-y-0 pb-14", className)}>
{cards.map((card, index) => {
const CardIcon = card.icon;
return (
<li
key={card.value}
className="sticky"
style={{ zIndex: index + 1, top: `${6 + 2.4 * index}rem` }}
>
<article
className={cn(
"flex h-100 flex-col justify-between rounded-[2.4rem] p-7 shadow-xl sm:p-9",
card.cardClassName ?? "bg-neutral-100 text-neutral-900",
)}
>
<div className="flex items-start justify-between gap-4">
<p className="text-7xl font-bold leading-none tracking-tighter sm:text-8xl">
{card.value}
<span className="align-top text-4xl">+</span>
</p>
<span
className={cn(
"inline-flex size-12 items-center justify-center rounded-full",
card.iconClassName ?? "bg-neutral-200 text-neutral-700",
)}
>
<CardIcon className="size-6" weight="Bold" />
</span>
</div>
<div className="max-w-xl">
<p className="text-xl font-bold leading-tight tracking-tight sm:text-3xl">
{card.title}
</p>
<p className="mt-4 text-base font-medium leading-relaxed opacity-95 sm:text-lg">
{card.description}
</p>
</div>
</article>
</li>
);
})}
</ul>
);
}
Update the import paths to match your project setup.
Similar components
Install via CLI
Resource details
PublishedJuly 17, 2026
CategoryCard
ReactTailwind CSSSolar Icons
Install via CLI
Resource details
PublishedJuly 17, 2026
CategoryCard
ReactTailwind CSSSolar Icons