36 Tailwind Stacked Cards
01 / 36

All 36 in 36 Tailwind Stacked Cards

  1. 01Tailwind Scroll-Driven Scaling Card Stack
  2. 02Tailwind Swipe Card Deck Drag to Dismiss
  3. 03Tailwind Glassmorphism Testimonial Card Stack
  4. 04Tailwind Stacked Cards Expand Accordion on Click
  5. 05Tailwind Fan Out Photo Stack on Hover
  6. 06Tailwind 3D Perspective Tilt Card Stack
  7. 07Tailwind Multi Step Form Card Stack
  8. 08Tailwind Tabbed Card Stack Bring to Front
  9. 09Tailwind Click to Front Stacked Cards Cycle
  10. 10Tailwind Classic Card Deck Stack Shadow
  11. 11Tailwind Fan Spread Hand of Cards
  12. 12Tailwind Polaroid Photo Stack Scattered Rotate
  13. 13Tailwind Staircase Offset Stacked Cards Cascade
  14. 14Tailwind Cards Spread Out Horizontally on Hover
  15. 15Tailwind Stacked Cards Lift on Hover Sibling Push
  16. 16Tailwind Accordion Stacked Cards Slide Out Menu
  17. 17Tailwind Shuffle Cards Animation Loop Deck
  18. 18Tailwind File Folder Tab Stacked Cards
  19. 19Tailwind Scattered Photos Pinch to Centre on Hover
  20. 20Tailwind Mobile Swipe Card Stack Translate3d
  21. 21Tailwind Single Accordion Card Nested Layers
  22. 22Tailwind Isometric Tower Stacked Cards 3D Column
  23. 23Tailwind 3D Flip Card Stack Reveal Back
  24. 24Tailwind Card Stack Tilt on Hover Quadrant
  25. 25Tailwind Notification Stack Pile Dismiss
  26. 26Tailwind Receipt Roll Unroll Stacked Items
  27. 27Tailwind Scratch Card Reveal Canvas Mask
  28. 28Tailwind Stacked Cards Hover Reveal Spread
  29. 29Tailwind Scroll Activated Sticky Stacking Cards
  30. 30Tailwind Stacked Testimonial Slider Radio
  31. 31Tailwind Isometric Overlapping Stacked Cards
  32. 32Tailwind Bento Grid Stacked Cards Hover Fan
  33. 33Tailwind Perspective Card Deck Depth Tunnel
  34. 34Tailwind Peel Back Corner Card Reveal
  35. 35Tailwind Timeline Stacked Milestone Cards
  36. 36Tailwind Spiral Tower Rotating Stacked Cards
Tailwind v4MIT licensed

Tailwind Scroll-Driven Scaling Card Stack

The storytelling hero, written in the markup. Each card is sticky with a stepped offset computed from its own --i, so top-[calc(90px+var(--i)*16px)] replaces four :nth-child rules. The scale-and-darken is an @theme animation — animate-stk01-shrink — driven by the two arbitrary properties Tailwind has no utility for, [animation-timeline:view()] and [animation-range:exit]. The only rules left in a stylesheet are the keyframes themselves.

Live Demo
Plain CSSTailwind v4
Try it

Untitled UI Pro: 5,000+ React + Tailwind CSS v4 components · from $349 one-time

Untitled UI React · Affiliate link

Get Untitled UI Pro

The code

<section class="stk-01 w-full min-h-svh h-svh overflow-y-auto bg-stk01-paper font-stk01-sans px-5 [scroll-behavior:smooth] motion-reduce:[scroll-behavior:auto]" aria-label="Scroll-driven scaling card stack">
  <div class="w-[min(520px,100%)] mx-auto pt-[14vh] pb-[40vh]">
    <p class="sticky top-4 z-10 m-0 text-center font-stk01-mono text-[11px] tracking-[0.16em] uppercase text-stk01-muted mb-[6vh]">Scroll &darr; inside this panel</p>
    <article class="sticky top-[calc(90px+var(--i)*16px)] h-65 mb-15 rounded-[22px] p-[34px] text-white bg-linear-[135deg,var(--color-stk01-a1),var(--color-stk01-a2)] shadow-[0_30px_60px_-34px_rgba(20,24,50,0.7)] animate-stk01-shrink [animation-timeline:view()] [animation-range:exit] motion-reduce:animate-none" style="--i:0">
      <span class="font-stk01-mono text-[13px] font-medium tracking-[0.2em] opacity-70">01</span>
      <h3 class="mt-3.5 mb-2.5 text-3xl font-extrabold tracking-[-0.02em]">Capture</h3>
      <p class="max-w-[34ch] text-base leading-relaxed opacity-90">Every idea starts as a rough note. We pin it before it escapes.</p>
    </article>
    <article class="sticky top-[calc(90px+var(--i)*16px)] h-65 mb-15 rounded-[22px] p-[34px] text-white bg-linear-[135deg,var(--color-stk01-b1),var(--color-stk01-b2)] shadow-[0_30px_60px_-34px_rgba(20,24,50,0.7)] animate-stk01-shrink [animation-timeline:view()] [animation-range:exit] motion-reduce:animate-none" style="--i:1">
      <span class="font-stk01-mono text-[13px] font-medium tracking-[0.2em] opacity-70">02</span>
      <h3 class="mt-3.5 mb-2.5 text-3xl font-extrabold tracking-[-0.02em]">Shape</h3>
      <p class="max-w-[34ch] text-base leading-relaxed opacity-90">Notes compress into a plan &mdash; the earlier one settles quietly behind.</p>
    </article>
    <article class="sticky top-[calc(90px+var(--i)*16px)] h-65 mb-15 rounded-[22px] p-[34px] text-white bg-linear-[135deg,var(--color-stk01-c1),var(--color-stk01-c2)] shadow-[0_30px_60px_-34px_rgba(20,24,50,0.7)] animate-stk01-shrink [animation-timeline:view()] [animation-range:exit] motion-reduce:animate-none" style="--i:2">
      <span class="font-stk01-mono text-[13px] font-medium tracking-[0.2em] opacity-70">03</span>
      <h3 class="mt-3.5 mb-2.5 text-3xl font-extrabold tracking-[-0.02em]">Ship</h3>
      <p class="max-w-[34ch] text-base leading-relaxed opacity-90">The plan surfaces on top, in focus, ready to hand off.</p>
    </article>
    <article class="sticky top-[calc(90px+var(--i)*16px)] h-65 mb-15 rounded-[22px] p-[34px] text-white bg-linear-[135deg,var(--color-stk01-d1),var(--color-stk01-d2)] shadow-[0_30px_60px_-34px_rgba(20,24,50,0.7)] animate-stk01-shrink [animation-timeline:view()] [animation-range:exit] motion-reduce:animate-none" style="--i:3">
      <span class="font-stk01-mono text-[13px] font-medium tracking-[0.2em] opacity-70">04</span>
      <h3 class="mt-3.5 mb-2.5 text-3xl font-extrabold tracking-[-0.02em]">Reflect</h3>
      <p class="max-w-[34ch] text-base leading-relaxed opacity-90">What worked stacks up as depth you can scroll back through.</p>
    </article>
    <div class="pt-[12vh] text-center font-stk01-mono text-sm tracking-[0.14em] uppercase text-stk01-muted">Fin.</div>
  </div>
</section>
@import "tailwindcss";

@theme {
  --color-stk01-paper: #eef0f4;
  --color-stk01-paper: oklch(0.945 0.006 265);
  --color-stk01-muted: #8a90a0;
  --color-stk01-muted: oklch(0.64 0.018 265);
  --color-stk01-a1: #6f6bf0;
  --color-stk01-a1: oklch(0.62 0.17 274);
  --color-stk01-a2: #8f5ce8;
  --color-stk01-a2: oklch(0.55 0.16 292);
  --color-stk01-b1: #3ec1d3;
  --color-stk01-b1: oklch(0.66 0.15 200);
  --color-stk01-b2: #4f8ee0;
  --color-stk01-b2: oklch(0.60 0.16 250);
  --color-stk01-c1: #4fd39a;
  --color-stk01-c1: oklch(0.70 0.15 150);
  --color-stk01-c2: #3bb7cf;
  --color-stk01-c2: oklch(0.62 0.15 200);
  --color-stk01-d1: #e9a53f;
  --color-stk01-d1: oklch(0.72 0.16 60);
  --color-stk01-d2: #e0713f;
  --color-stk01-d2: oklch(0.64 0.17 30);
  --font-stk01-sans: 'Archivo', system-ui, sans-serif;
  --font-stk01-mono: 'JetBrains Mono', ui-monospace, monospace;
  --animate-stk01-shrink: stk-01-shrink linear both;
}
/* Keyframes are a rule, not a value: there is no utility form for them, and the
   @theme --animate-* entry above only names this block. */

@keyframes stk-01-shrink {
  to {
    transform: scale(0.9);
    filter: brightness(0.72);
  }
}

Setup — do this once per project

Skip this if your project already runs Tailwind v4.

1Load Tailwind
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>

Compiles in the browser — perfect for a CodePen or a quick test, not for production.

2Add the stylesheetRequiredthe @theme block is what makes the custom utilities exist
@import "tailwindcss";

@theme {
  --color-stk01-paper: #eef0f4;
  --color-stk01-paper: oklch(0.945 0.006 265);
  --color-stk01-muted: #8a90a0;
  --color-stk01-muted: oklch(0.64 0.018 265);
  --color-stk01-a1: #6f6bf0;
  --color-stk01-a1: oklch(0.62 0.17 274);
  --color-stk01-a2: #8f5ce8;
  --color-stk01-a2: oklch(0.55 0.16 292);
  --color-stk01-b1: #3ec1d3;
  --color-stk01-b1: oklch(0.66 0.15 200);
  --color-stk01-b2: #4f8ee0;
  --color-stk01-b2: oklch(0.60 0.16 250);
  --color-stk01-c1: #4fd39a;
  --color-stk01-c1: oklch(0.70 0.15 150);
  --color-stk01-c2: #3bb7cf;
  --color-stk01-c2: oklch(0.62 0.15 200);
  --color-stk01-d1: #e9a53f;
  --color-stk01-d1: oklch(0.72 0.16 60);
  --color-stk01-d2: #e0713f;
  --color-stk01-d2: oklch(0.64 0.17 30);
  --font-stk01-sans: 'Archivo', system-ui, sans-serif;
  --font-stk01-mono: 'JetBrains Mono', ui-monospace, monospace;
  --animate-stk01-shrink: stk-01-shrink linear both;
}
/* Keyframes are a rule, not a value: there is no utility form for them, and the
   @theme --animate-* entry above only names this block. */

@keyframes stk-01-shrink {
  to {
    transform: scale(0.9);
    filter: brightness(0.72);
  }
}
3Fonts used by this demooptional — skip if you have your own type stack
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Archivo:wdth,wght@75..125,400;75..125,600;75..125,800&family=JetBrains+Mono:wght@400;500&display=swap">

What changed in the port

Which parts became utilities, which stayed CSS, and why.

  • The webfonts load as <link> tags in setup, not as an @import inside the stylesheet. Tailwind emits user @import rules after its own @layer blocks, and a late @import is invalid CSS — the browser drops it and the demo silently falls back to system fonts.
  • Four :nth-child sticky-offset rules collapse into one utility reading a per-card custom property: style=&quot;--i:2&quot; plus top-[calc(90px+var(--i)*16px)].
  • The four :nth-child gradient rules disappear entirely — each card carries its own bg-linear-[...], so recolouring one card touches one element.
  • --animate-stk01-shrink in @theme mints animate-stk01-shrink with its timing baked in; only the @keyframes block has to stay in CSS.
  • animation-timeline and animation-range have no utilities and should not — [animation-timeline:view()] [animation-range:exit] sits on the card next to the animation it drives.
  • The reduced-motion block becomes two variants in the markup: motion-reduce:animate-none on the cards and motion-reduce:[scroll-behavior:auto] on the scroller.
  • Height stays fixed (h-65 = 260px) rather than fluid, because sticky offsets and a zero CLS score both need the box reserved up front.
Paste this into ChatGPT, Claude, Cursor, or any coding assistant. The block below is pre-framed with everything the AI needs to integrate this demo into your project — markup, styles, scoping notes, and the source URL. Hit Copy and paste straight into your chat.
Here's a working CSS demo from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: Tailwind Scroll-Driven Scaling Card Stack
Source: https://codefronts.com/components/tailwind-stacked-cards/tailwind-scroll-driven-scaling-card-stack/

The storytelling hero, written in the markup. Each card is sticky with a stepped offset computed from its own --i, so top-[calc(90px+var(--i)*16px)] replaces four :nth-child rules. The scale-and-darken is an @theme animation — animate-stk01-shrink — driven by the two arbitrary properties Tailwind has no utility for, [animation-timeline:view()] and [animation-range:exit]. The only rules left in a stylesheet are the keyframes themselves.
## HTML
```html
<section class="stk-01 w-full min-h-svh h-svh overflow-y-auto bg-stk01-paper font-stk01-sans px-5 [scroll-behavior:smooth] motion-reduce:[scroll-behavior:auto]" aria-label="Scroll-driven scaling card stack">
  <div class="w-[min(520px,100%)] mx-auto pt-[14vh] pb-[40vh]">
    <p class="sticky top-4 z-10 m-0 text-center font-stk01-mono text-[11px] tracking-[0.16em] uppercase text-stk01-muted mb-[6vh]">Scroll &darr; inside this panel</p>
    <article class="sticky top-[calc(90px+var(--i)*16px)] h-65 mb-15 rounded-[22px] p-[34px] text-white bg-linear-[135deg,var(--color-stk01-a1),var(--color-stk01-a2)] shadow-[0_30px_60px_-34px_rgba(20,24,50,0.7)] animate-stk01-shrink [animation-timeline:view()] [animation-range:exit] motion-reduce:animate-none" style="--i:0">
      <span class="font-stk01-mono text-[13px] font-medium tracking-[0.2em] opacity-70">01</span>
      <h3 class="mt-3.5 mb-2.5 text-3xl font-extrabold tracking-[-0.02em]">Capture</h3>
      <p class="max-w-[34ch] text-base leading-relaxed opacity-90">Every idea starts as a rough note. We pin it before it escapes.</p>
    </article>
    <article class="sticky top-[calc(90px+var(--i)*16px)] h-65 mb-15 rounded-[22px] p-[34px] text-white bg-linear-[135deg,var(--color-stk01-b1),var(--color-stk01-b2)] shadow-[0_30px_60px_-34px_rgba(20,24,50,0.7)] animate-stk01-shrink [animation-timeline:view()] [animation-range:exit] motion-reduce:animate-none" style="--i:1">
      <span class="font-stk01-mono text-[13px] font-medium tracking-[0.2em] opacity-70">02</span>
      <h3 class="mt-3.5 mb-2.5 text-3xl font-extrabold tracking-[-0.02em]">Shape</h3>
      <p class="max-w-[34ch] text-base leading-relaxed opacity-90">Notes compress into a plan &mdash; the earlier one settles quietly behind.</p>
    </article>
    <article class="sticky top-[calc(90px+var(--i)*16px)] h-65 mb-15 rounded-[22px] p-[34px] text-white bg-linear-[135deg,var(--color-stk01-c1),var(--color-stk01-c2)] shadow-[0_30px_60px_-34px_rgba(20,24,50,0.7)] animate-stk01-shrink [animation-timeline:view()] [animation-range:exit] motion-reduce:animate-none" style="--i:2">
      <span class="font-stk01-mono text-[13px] font-medium tracking-[0.2em] opacity-70">03</span>
      <h3 class="mt-3.5 mb-2.5 text-3xl font-extrabold tracking-[-0.02em]">Ship</h3>
      <p class="max-w-[34ch] text-base leading-relaxed opacity-90">The plan surfaces on top, in focus, ready to hand off.</p>
    </article>
    <article class="sticky top-[calc(90px+var(--i)*16px)] h-65 mb-15 rounded-[22px] p-[34px] text-white bg-linear-[135deg,var(--color-stk01-d1),var(--color-stk01-d2)] shadow-[0_30px_60px_-34px_rgba(20,24,50,0.7)] animate-stk01-shrink [animation-timeline:view()] [animation-range:exit] motion-reduce:animate-none" style="--i:3">
      <span class="font-stk01-mono text-[13px] font-medium tracking-[0.2em] opacity-70">04</span>
      <h3 class="mt-3.5 mb-2.5 text-3xl font-extrabold tracking-[-0.02em]">Reflect</h3>
      <p class="max-w-[34ch] text-base leading-relaxed opacity-90">What worked stacks up as depth you can scroll back through.</p>
    </article>
    <div class="pt-[12vh] text-center font-stk01-mono text-sm tracking-[0.14em] uppercase text-stk01-muted">Fin.</div>
  </div>
</section>
```
## CSS
```css
@import "tailwindcss";

@theme {
  --color-stk01-paper: #eef0f4;
  --color-stk01-paper: oklch(0.945 0.006 265);
  --color-stk01-muted: #8a90a0;
  --color-stk01-muted: oklch(0.64 0.018 265);
  --color-stk01-a1: #6f6bf0;
  --color-stk01-a1: oklch(0.62 0.17 274);
  --color-stk01-a2: #8f5ce8;
  --color-stk01-a2: oklch(0.55 0.16 292);
  --color-stk01-b1: #3ec1d3;
  --color-stk01-b1: oklch(0.66 0.15 200);
  --color-stk01-b2: #4f8ee0;
  --color-stk01-b2: oklch(0.60 0.16 250);
  --color-stk01-c1: #4fd39a;
  --color-stk01-c1: oklch(0.70 0.15 150);
  --color-stk01-c2: #3bb7cf;
  --color-stk01-c2: oklch(0.62 0.15 200);
  --color-stk01-d1: #e9a53f;
  --color-stk01-d1: oklch(0.72 0.16 60);
  --color-stk01-d2: #e0713f;
  --color-stk01-d2: oklch(0.64 0.17 30);
  --font-stk01-sans: 'Archivo', system-ui, sans-serif;
  --font-stk01-mono: 'JetBrains Mono', ui-monospace, monospace;
  --animate-stk01-shrink: stk-01-shrink linear both;
}
/* Keyframes are a rule, not a value: there is no utility form for them, and the
   @theme --animate-* entry above only names this block. */

@keyframes stk-01-shrink {
  to {
    transform: scale(0.9);
    filter: brightness(0.72);
  }
}
```

How this works

The index goes on the element, not in a rule. A CSS stack needs one :nth-child block per card to step the sticky offset. In utilities you cannot write that from the child, so the number rides the element as a custom property and every derived utility reads it:

<article style="--i:2"
  class="sticky top-[calc(90px+var(--i)*16px)] h-65 …">

Add a fifth card and it takes its place with no re-indexing anywhere. This pattern recurs in more than half the collection, and it is the single biggest structural difference from the hand-written version.

The animation is a token. --animate-stk01-shrink: stk-01-shrink linear both in @theme gives a real animate-stk01-shrink utility that carries its own timing function and fill mode, so the element needs one class rather than four declarations. The @keyframes block stays in CSS — keyframes are a rule, not a value.

Scroll-driving stays arbitrary, correctly. animation-timeline and animation-range are not design-scale properties and Tailwind ships no scale for them. [animation-timeline:view()] [animation-range:exit] is the idiomatic answer, and it reads as exactly what it is: this animation's clock is the card's own trip through the viewport.

The fallback is free. Where animation-timeline is unsupported the animation simply never advances, so the card sits at its unanimated state and the reader gets a clean sticky stack. Nothing needs a feature query.

Make it yours

  • Tune the compression by editing the scale() and brightness() end values in the keyframes — the one place this demo still needs CSS.
  • Change how much each pinned card peeks by editing the 16px step inside top-[calc(90px+var(--i)*16px)].
  • Swap [animation-range:exit] for [animation-range:cover] to start the scale earlier in the card's travel.
  • Recolour a single card by editing its own bg-linear-[...] utility; there is no colour map to keep in sync.
  • Add a card by copying one <article> and incrementing its --i.

Gotchas — read before shipping

  • Keep the fixed height (h-65) on every card. Sticky math and CLS both depend on the box being reserved before paint.
  • animation-timeline needs Chrome/Edge 115+ or Safari 26+. Do not feature-query it — the unsupported path already degrades to a plain sticky stack.
  • Never animate width/height for the shrink. animate-stk01-shrink moves transform and filter, which stay on the compositor.
  • Arbitrary values cannot contain spaces. top-[calc(90px+var(--i)*16px)] must be typed closed-up, or use the underscore escape.
  • The class string must be statically visible to the compiler. top-[calc(90px+var(--i)*{{step}}px)] built at runtime produces nothing — keep the arithmetic in CSS and the varying part in the custom property.
  • The browser CDN build compiles in the page and is for prototyping only. Ship the CLI or a plugin build.

Browser support

ChromeSafariFirefoxEdge
115+26+128+ (sticky stack only)115+

Tailwind v4 itself needs Chrome 111+, Safari 16.4+, Firefox 128+. position:sticky is universal, so the stack always reads; the scale-and-darken is a progressive enhancement on animation-timeline:view() and simply does not run where that is missing.

Techniques used in this demo

Theme tokensset in @theme, used by a utility

Arbitraryneeds bracket syntax

Plain CSSno Tailwind surface

Search CodeFronts

Loading…