36 Tailwind Stacked Cards
10 / 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 Classic Card Deck Stack Shadow

Depth from tone and shadow alone — no colour tricks, no 3D. Four cards share a footprint, stepped by [transform:translate(calc(var(--i)*5px),calc(var(--i)*6px))], and the thickness comes from a two-layer shadow: a hard 2px offset for the cut edge, a soft blur for the drop. On hover the same expression runs at a larger step, so one utility describes both the resting deck and the spread.

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-10 w-full min-h-svh flex items-center justify-center px-5 py-15 font-stk10-sans bg-stk10-paper" aria-label="Classic card deck">
  <div class="group relative w-[min(320px,100%)] h-55 rounded-[20px] outline-none focus-visible:outline-3 focus-visible:outline-stk10-accent focus-visible:outline-offset-8" tabindex="0">
    <div class="absolute inset-0 rounded-2xl border border-stk10-line bg-stk10-under shadow-[0_2px_0_var(--color-stk10-edge),0_12px_24px_-14px_rgba(60,50,30,0.5)] [transform:translate(calc(var(--i)*5px),calc(var(--i)*6px))] transition-transform duration-400 ease-stk10 group-hover:[transform:translate(calc(var(--i)*12px),calc(var(--i)*13px))] group-focus-visible:[transform:translate(calc(var(--i)*12px),calc(var(--i)*13px))] motion-reduce:transition-none" style="--i:3" aria-hidden="true"></div>
    <div class="absolute inset-0 rounded-2xl border border-stk10-line bg-stk10-under shadow-[0_2px_0_var(--color-stk10-edge),0_12px_24px_-14px_rgba(60,50,30,0.5)] [transform:translate(calc(var(--i)*5px),calc(var(--i)*6px))] transition-transform duration-400 ease-stk10 group-hover:[transform:translate(calc(var(--i)*12px),calc(var(--i)*13px))] group-focus-visible:[transform:translate(calc(var(--i)*12px),calc(var(--i)*13px))] motion-reduce:transition-none" style="--i:2" aria-hidden="true"></div>
    <div class="absolute inset-0 rounded-2xl border border-stk10-line bg-stk10-under shadow-[0_2px_0_var(--color-stk10-edge),0_12px_24px_-14px_rgba(60,50,30,0.5)] [transform:translate(calc(var(--i)*5px),calc(var(--i)*6px))] transition-transform duration-400 ease-stk10 group-hover:[transform:translate(calc(var(--i)*12px),calc(var(--i)*13px))] group-focus-visible:[transform:translate(calc(var(--i)*12px),calc(var(--i)*13px))] motion-reduce:transition-none" style="--i:1" aria-hidden="true"></div>
    <div class="absolute inset-0 z-5 rounded-2xl border border-stk10-line bg-stk10-face p-7 shadow-[0_3px_0_var(--color-stk10-edge),0_20px_34px_-18px_rgba(60,50,30,0.55)] [transform:translate(calc(var(--i)*5px),calc(var(--i)*6px))] transition-transform duration-400 ease-stk10 group-hover:[transform:translate(calc(var(--i)*12px),calc(var(--i)*13px))] group-focus-visible:[transform:translate(calc(var(--i)*12px),calc(var(--i)*13px))] motion-reduce:transition-none" style="--i:0">
      <p class="m-0 font-stk10-mono text-xs font-medium tracking-[0.16em] uppercase text-stk10-accent">Field Notes</p>
      <h3 class="mt-2 mb-2.5 text-3xl font-extrabold tracking-[-0.02em] text-stk10-ink">Deck No.&thinsp;7</h3>
      <p class="m-0 max-w-[32ch] text-[15px] leading-relaxed text-stk10-body">Fifty-two ideas, shuffled weekly. Draw one and build it before Friday.</p>
    </div>
  </div>
</section>
@import "tailwindcss";

@theme {
  --color-stk10-paper: #e7e4dc;
  --color-stk10-paper: oklch(0.91 0.008 85);
  --color-stk10-face: #fdfcf9;
  --color-stk10-face: oklch(0.99 0.004 85);
  --color-stk10-under: #f6f3ec;
  --color-stk10-under: oklch(0.96 0.007 85);
  --color-stk10-line: #e0dcd0;
  --color-stk10-line: oklch(0.89 0.010 85);
  --color-stk10-edge: #d9d4c6;
  --color-stk10-edge: oklch(0.86 0.014 85);
  --color-stk10-ink: #3a3324;
  --color-stk10-ink: oklch(0.33 0.020 80);
  --color-stk10-body: #6a6250;
  --color-stk10-body: oklch(0.50 0.018 80);
  --color-stk10-accent: #a89b7c;
  --color-stk10-accent: oklch(0.68 0.035 85);
  --font-stk10-sans: 'Archivo', system-ui, sans-serif;
  --font-stk10-mono: 'JetBrains Mono', ui-monospace, monospace;
  --ease-stk10: cubic-bezier(0.3, 0.9, 0.3, 1);
}

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-stk10-paper: #e7e4dc;
  --color-stk10-paper: oklch(0.91 0.008 85);
  --color-stk10-face: #fdfcf9;
  --color-stk10-face: oklch(0.99 0.004 85);
  --color-stk10-under: #f6f3ec;
  --color-stk10-under: oklch(0.96 0.007 85);
  --color-stk10-line: #e0dcd0;
  --color-stk10-line: oklch(0.89 0.010 85);
  --color-stk10-edge: #d9d4c6;
  --color-stk10-edge: oklch(0.86 0.014 85);
  --color-stk10-ink: #3a3324;
  --color-stk10-ink: oklch(0.33 0.020 80);
  --color-stk10-body: #6a6250;
  --color-stk10-body: oklch(0.50 0.018 80);
  --color-stk10-accent: #a89b7c;
  --color-stk10-accent: oklch(0.68 0.035 85);
  --font-stk10-sans: 'Archivo', system-ui, sans-serif;
  --font-stk10-mono: 'JetBrains Mono', ui-monospace, monospace;
  --ease-stk10: cubic-bezier(0.3, 0.9, 0.3, 1);
}
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,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.
  • Eight rules — four resting offsets and four hover twins — become one arbitrary transform and one group-hover: override, both reading --i.
  • The layered box-shadow stays arbitrary, and the hard 0_2px_0 layer is the whole effect: it is the cut edge of the paper, and no amount of blur substitutes for it.
  • Tonal separation is two @theme colours rather than an opacity modifier, because a translucent top card lets the under-card fill bleed through.
  • :not(.card--top) disappears — the under-cards simply carry bg-stk10-under and the top card carries bg-stk10-face.
  • The whole demo is four <div>s and a @theme block: no keyframes, no :has(), no script, and the only custom property is an integer.
  • Arbitrary transforms replace rather than compose, so the group-hover: value repeats both axes — a partial override would silently drop one.
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 Classic Card Deck Stack Shadow
Source: https://codefronts.com/components/tailwind-stacked-cards/tailwind-classic-card-deck-stack-shadow/

Depth from tone and shadow alone &mdash; no colour tricks, no 3D. Four cards share a footprint, stepped by [transform:translate(calc(var(--i)*5px),calc(var(--i)*6px))], and the thickness comes from a two-layer shadow: a hard 2px offset for the cut edge, a soft blur for the drop. On hover the same expression runs at a larger step, so one utility describes both the resting deck and the spread.
## HTML
```html
<section class="stk-10 w-full min-h-svh flex items-center justify-center px-5 py-15 font-stk10-sans bg-stk10-paper" aria-label="Classic card deck">
  <div class="group relative w-[min(320px,100%)] h-55 rounded-[20px] outline-none focus-visible:outline-3 focus-visible:outline-stk10-accent focus-visible:outline-offset-8" tabindex="0">
    <div class="absolute inset-0 rounded-2xl border border-stk10-line bg-stk10-under shadow-[0_2px_0_var(--color-stk10-edge),0_12px_24px_-14px_rgba(60,50,30,0.5)] [transform:translate(calc(var(--i)*5px),calc(var(--i)*6px))] transition-transform duration-400 ease-stk10 group-hover:[transform:translate(calc(var(--i)*12px),calc(var(--i)*13px))] group-focus-visible:[transform:translate(calc(var(--i)*12px),calc(var(--i)*13px))] motion-reduce:transition-none" style="--i:3" aria-hidden="true"></div>
    <div class="absolute inset-0 rounded-2xl border border-stk10-line bg-stk10-under shadow-[0_2px_0_var(--color-stk10-edge),0_12px_24px_-14px_rgba(60,50,30,0.5)] [transform:translate(calc(var(--i)*5px),calc(var(--i)*6px))] transition-transform duration-400 ease-stk10 group-hover:[transform:translate(calc(var(--i)*12px),calc(var(--i)*13px))] group-focus-visible:[transform:translate(calc(var(--i)*12px),calc(var(--i)*13px))] motion-reduce:transition-none" style="--i:2" aria-hidden="true"></div>
    <div class="absolute inset-0 rounded-2xl border border-stk10-line bg-stk10-under shadow-[0_2px_0_var(--color-stk10-edge),0_12px_24px_-14px_rgba(60,50,30,0.5)] [transform:translate(calc(var(--i)*5px),calc(var(--i)*6px))] transition-transform duration-400 ease-stk10 group-hover:[transform:translate(calc(var(--i)*12px),calc(var(--i)*13px))] group-focus-visible:[transform:translate(calc(var(--i)*12px),calc(var(--i)*13px))] motion-reduce:transition-none" style="--i:1" aria-hidden="true"></div>
    <div class="absolute inset-0 z-5 rounded-2xl border border-stk10-line bg-stk10-face p-7 shadow-[0_3px_0_var(--color-stk10-edge),0_20px_34px_-18px_rgba(60,50,30,0.55)] [transform:translate(calc(var(--i)*5px),calc(var(--i)*6px))] transition-transform duration-400 ease-stk10 group-hover:[transform:translate(calc(var(--i)*12px),calc(var(--i)*13px))] group-focus-visible:[transform:translate(calc(var(--i)*12px),calc(var(--i)*13px))] motion-reduce:transition-none" style="--i:0">
      <p class="m-0 font-stk10-mono text-xs font-medium tracking-[0.16em] uppercase text-stk10-accent">Field Notes</p>
      <h3 class="mt-2 mb-2.5 text-3xl font-extrabold tracking-[-0.02em] text-stk10-ink">Deck No.&thinsp;7</h3>
      <p class="m-0 max-w-[32ch] text-[15px] leading-relaxed text-stk10-body">Fifty-two ideas, shuffled weekly. Draw one and build it before Friday.</p>
    </div>
  </div>
</section>
```
## CSS
```css
@import "tailwindcss";

@theme {
  --color-stk10-paper: #e7e4dc;
  --color-stk10-paper: oklch(0.91 0.008 85);
  --color-stk10-face: #fdfcf9;
  --color-stk10-face: oklch(0.99 0.004 85);
  --color-stk10-under: #f6f3ec;
  --color-stk10-under: oklch(0.96 0.007 85);
  --color-stk10-line: #e0dcd0;
  --color-stk10-line: oklch(0.89 0.010 85);
  --color-stk10-edge: #d9d4c6;
  --color-stk10-edge: oklch(0.86 0.014 85);
  --color-stk10-ink: #3a3324;
  --color-stk10-ink: oklch(0.33 0.020 80);
  --color-stk10-body: #6a6250;
  --color-stk10-body: oklch(0.50 0.018 80);
  --color-stk10-accent: #a89b7c;
  --color-stk10-accent: oklch(0.68 0.035 85);
  --font-stk10-sans: 'Archivo', system-ui, sans-serif;
  --font-stk10-mono: 'JetBrains Mono', ui-monospace, monospace;
  --ease-stk10: cubic-bezier(0.3, 0.9, 0.3, 1);
}
```

How this works

One expression, two multipliers. The resting step and the hover spread are the same shape of value:

[transform:translate(calc(var(--i)*5px),calc(var(--i)*6px))]
group-hover:[transform:translate(calc(var(--i)*12px),calc(var(--i)*13px))]

Four :nth-child offsets and their four hover twins collapse to this, and the deck's depth is now a single number you can tune without counting cards.

Thickness is two shadows, not one. A blurred shadow alone gives a floating card; a card with an edge needs a zero-blur offset first — 0_2px_0_var(--color-stk10-edge) — and the blur second. The top card gets a slightly deeper pair so it reads as the thing you would pick up.

The under-cards are furniture. They carry no content and are marked aria-hidden, so a screen reader hears one card with one title, which is what the design actually means. The top card stays fully opaque, because a translucent face would let the lower fills bleed through and destroy the tonal separation the whole effect depends on.

Make it yours

  • Deepen the deck by adding a card with the next --i; nothing else changes.
  • Tune the thickness by editing the hard 0_2px_0 layer and its --color-stk10-edge token.
  • Change the spread with the 12px / 13px multipliers in the group-hover: transform.
  • Restyle the top card's content freely — it is the only card with any.
  • Swap the paper palette through --color-stk10-face / -under / -edge.

Gotchas — read before shipping

  • Mark the decorative cards aria-hidden. Four identical empty cards in the accessibility tree is noise, not depth.
  • Keep the top card opaque. Any transparency and the under-card tone shows through as a muddy tint.
  • Use an offset shadow with zero blur for the edge. Blur alone always reads as float, never as thickness.
  • The hover transform must repeat the whole translate(). Arbitrary transforms replace rather than compose, so a partial value loses the other axis.
  • Put the focus ring on the wrapper, not the cards; the cards are decorative and the wrapper is what receives focus.
  • Give the stage room for the spread — at --i:3 the hover offset is 36px right and 39px down.

Browser support

ChromeSafariFirefoxEdge
111+16.4+128+111+

Transforms, calc() with custom properties and layered box-shadow are universal (Chrome 49+, Safari 10+, Firefox 52+). The floor is Tailwind v4's own generated sheet.

Techniques used in this demo

Theme tokensset in @theme, used by a utility

Arbitraryneeds bracket syntax

HTML & JSno Tailwind involved

Search CodeFronts

Loading…