36 Tailwind Stacked Cards
32 / 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 Bento Grid Stacked Cards Hover Fan

A dashboard bento where one tile hides a stacked mini-deck: three channel breakdowns collapsed into a single cell that fans open on hover. This is the demo where Tailwind's grid utilities do the heavy lifting for free — col-span-2, row-span-2 and a fixed track list replace named grid areas entirely — while the fan itself is the index pattern one more time.

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-32 grid w-full min-h-svh place-items-center p-5 font-stk32-sans bg-stk32-bg" aria-label="Analytics dashboard preview">
  <div class="grid grid-cols-[repeat(3,118px)] grid-rows-[repeat(3,118px)] gap-3">
    <div class="group relative z-5 row-span-2 overflow-visible rounded-[18px] border border-stk32-line bg-stk32-tile p-4 transition-colors duration-300 hover:z-20 hover:border-stk32-lineh">
      <span class="text-[0.68rem] tracking-[0.12em] uppercase text-stk32-lbl">Channels</span>
      <div class="absolute inset-x-4 bottom-3.5 h-13.5">
        <div class="pointer-events-none absolute inset-x-0 h-13.5 rounded-xl bg-stk32-m1 px-3 py-2 text-[0.72rem] text-white shadow-[0_8px_18px_rgba(0,0,0,0.55)] [z-index:calc(3-var(--i))] transition-transform duration-450 ease-stk32 group-hover:[transform:translateY(calc(var(--i)*-58px))] motion-reduce:transition-none" style="--i:0">
          <span class="text-[0.68rem] tracking-[0.12em] uppercase text-white/85">Organic</span>
          <b class="mt-0.5 block text-[0.95rem]">62%</b>
        </div>
        <div class="pointer-events-none absolute inset-x-0 h-13.5 rounded-xl bg-stk32-m2 px-3 py-2 text-[0.72rem] text-white shadow-[0_8px_18px_rgba(0,0,0,0.55)] [z-index:calc(3-var(--i))] transition-transform duration-450 ease-stk32 group-hover:[transform:translateY(calc(var(--i)*-58px))] motion-reduce:transition-none" style="--i:1">
          <span class="text-[0.68rem] tracking-[0.12em] uppercase text-white/85">Paid</span>
          <b class="mt-0.5 block text-[0.95rem]">24%</b>
        </div>
        <div class="pointer-events-none absolute inset-x-0 h-13.5 rounded-xl bg-stk32-m3 px-3 py-2 text-[0.72rem] text-white shadow-[0_8px_18px_rgba(0,0,0,0.55)] [z-index:calc(3-var(--i))] transition-transform duration-450 ease-stk32 group-hover:[transform:translateY(calc(var(--i)*-58px))] motion-reduce:transition-none" style="--i:2">
          <span class="text-[0.68rem] tracking-[0.12em] uppercase text-white/85">Referral</span>
          <b class="mt-0.5 block text-[0.95rem]">14%</b>
        </div>
      </div>
    </div>
    <div class="relative col-span-2 overflow-hidden rounded-[18px] border border-stk32-line bg-stk32-tile p-4 transition-colors duration-300 hover:border-stk32-lineh">
      <div class="pointer-events-none absolute -right-8 -top-8 size-24 rounded-full bg-stk32-good opacity-20 blur-2xl" aria-hidden="true"></div>
      <span class="text-[0.68rem] tracking-[0.12em] uppercase text-stk32-lbl">Revenue</span>
      <div class="mt-1 text-[1.6rem] font-bold text-stk32-val">$48.2k <small class="text-[0.8rem] font-semibold text-stk32-good">+12%</small></div>
      <div class="mt-2 flex h-8 items-end gap-1.5" aria-hidden="true">
        <span class="w-2 rounded-t bg-stk32-bar" style="height:40%"></span>
        <span class="w-2 rounded-t bg-stk32-bar" style="height:55%"></span>
        <span class="w-2 rounded-t bg-stk32-bar" style="height:45%"></span>
        <span class="w-2 rounded-t bg-stk32-bar" style="height:70%"></span>
        <span class="w-2 rounded-t bg-stk32-bar" style="height:60%"></span>
        <span class="w-2 rounded-t bg-stk32-bar" style="height:85%"></span>
        <span class="w-2 rounded-t bg-stk32-good" style="height:100%"></span>
      </div>
    </div>
    <div class="relative overflow-hidden rounded-[18px] border border-stk32-line bg-stk32-tile p-4 transition-colors duration-300 hover:border-stk32-lineh">
      <span class="text-[0.68rem] tracking-[0.12em] uppercase text-stk32-lbl">Users</span>
      <div class="mt-1 text-[1.6rem] font-bold text-stk32-val">9.1k</div>
    </div>
    <div class="relative overflow-hidden rounded-[18px] border border-stk32-line bg-stk32-tile p-4 transition-colors duration-300 hover:border-stk32-lineh">
      <span class="text-[0.68rem] tracking-[0.12em] uppercase text-stk32-lbl">Churn</span>
      <div class="mt-1 text-[1.6rem] font-bold text-stk32-bad">1.8%</div>
    </div>
    <div class="relative overflow-hidden rounded-[18px] border border-stk32-line bg-stk32-tile p-4 transition-colors duration-300 hover:border-stk32-lineh">
      <div class="pointer-events-none absolute -left-8 -bottom-8 size-24 rounded-full bg-stk32-m1 opacity-25 blur-2xl" aria-hidden="true"></div>
      <span class="text-[0.68rem] tracking-[0.12em] uppercase text-stk32-lbl">NPS</span>
      <div class="mt-1 text-[1.6rem] font-bold text-stk32-val">72</div>
    </div>
  </div>
</section>
@import "tailwindcss";

@theme {
  --color-stk32-bg: #0e0f13;
  --color-stk32-bg: oklch(0.17 0.008 275);
  --color-stk32-tile: #191b22;
  --color-stk32-tile: oklch(0.23 0.012 275);
  --color-stk32-line: #262934;
  --color-stk32-line: oklch(0.30 0.014 275);
  --color-stk32-lineh: #3a4050;
  --color-stk32-lineh: oklch(0.40 0.018 275);
  --color-stk32-lbl: #8a90a0;
  --color-stk32-lbl: oklch(0.64 0.016 275);
  --color-stk32-val: #f3f4f6;
  --color-stk32-val: oklch(0.97 0.003 275);
  --color-stk32-bar: #4b5162;
  --color-stk32-bar: oklch(0.46 0.020 275);
  --color-stk32-good: #34d399;
  --color-stk32-good: oklch(0.78 0.15 165);
  --color-stk32-bad: #fca5a5;
  --color-stk32-bad: oklch(0.79 0.10 20);
  --color-stk32-m1: #818cf8;
  --color-stk32-m1: oklch(0.68 0.15 280);
  --color-stk32-m2: #f472b6;
  --color-stk32-m2: oklch(0.72 0.17 350);
  --color-stk32-m3: #2dd4bf;
  --color-stk32-m3: oklch(0.79 0.13 180);
  --font-stk32-sans: 'Geist', system-ui, sans-serif;
  --ease-stk32: 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-stk32-bg: #0e0f13;
  --color-stk32-bg: oklch(0.17 0.008 275);
  --color-stk32-tile: #191b22;
  --color-stk32-tile: oklch(0.23 0.012 275);
  --color-stk32-line: #262934;
  --color-stk32-line: oklch(0.30 0.014 275);
  --color-stk32-lineh: #3a4050;
  --color-stk32-lineh: oklch(0.40 0.018 275);
  --color-stk32-lbl: #8a90a0;
  --color-stk32-lbl: oklch(0.64 0.016 275);
  --color-stk32-val: #f3f4f6;
  --color-stk32-val: oklch(0.97 0.003 275);
  --color-stk32-bar: #4b5162;
  --color-stk32-bar: oklch(0.46 0.020 275);
  --color-stk32-good: #34d399;
  --color-stk32-good: oklch(0.78 0.15 165);
  --color-stk32-bad: #fca5a5;
  --color-stk32-bad: oklch(0.79 0.10 20);
  --color-stk32-m1: #818cf8;
  --color-stk32-m1: oklch(0.68 0.15 280);
  --color-stk32-m2: #f472b6;
  --color-stk32-m2: oklch(0.72 0.17 350);
  --color-stk32-m3: #2dd4bf;
  --color-stk32-m3: oklch(0.79 0.13 180);
  --font-stk32-sans: 'Geist', system-ui, sans-serif;
  --ease-stk32: 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=Geist:wght@400;500;600;700&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.
  • Named grid areas disappear: an explicit track list plus col-span-2 and row-span-2 says the same thing with no naming layer. Areas earn their keep only when the layout changes shape across breakpoints.
  • The one tile that must escape its cell declares it on itself — overflow-visible plus hover:z-20 — while every other tile stays clipped.
  • The nested fan is the same index pattern used in demos 05, 13, 22 and 32: one custom property, one multiplied transform.
  • pointer-events-none on the mini-cards is load-bearing; without it they intercept the hover meant for the tile fanning them.
  • The sparkline is real elements with inline heights rather than an SVG, and the whole group is aria-hidden because the number beside it is the actual content.
  • Accent glows are blurred circles rather than gradient overlays, which keeps each one a single element and removes the CSS version's inline style=&quot;background:…&quot;.
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 Bento Grid Stacked Cards Hover Fan
Source: https://codefronts.com/components/tailwind-stacked-cards/tailwind-bento-grid-stacked-cards-hover-fan/

A dashboard bento where one tile hides a stacked mini-deck: three channel breakdowns collapsed into a single cell that fans open on hover. This is the demo where Tailwind's grid utilities do the heavy lifting for free &mdash; col-span-2, row-span-2 and a fixed track list replace named grid areas entirely &mdash; while the fan itself is the index pattern one more time.
## HTML
```html
<section class="stk-32 grid w-full min-h-svh place-items-center p-5 font-stk32-sans bg-stk32-bg" aria-label="Analytics dashboard preview">
  <div class="grid grid-cols-[repeat(3,118px)] grid-rows-[repeat(3,118px)] gap-3">
    <div class="group relative z-5 row-span-2 overflow-visible rounded-[18px] border border-stk32-line bg-stk32-tile p-4 transition-colors duration-300 hover:z-20 hover:border-stk32-lineh">
      <span class="text-[0.68rem] tracking-[0.12em] uppercase text-stk32-lbl">Channels</span>
      <div class="absolute inset-x-4 bottom-3.5 h-13.5">
        <div class="pointer-events-none absolute inset-x-0 h-13.5 rounded-xl bg-stk32-m1 px-3 py-2 text-[0.72rem] text-white shadow-[0_8px_18px_rgba(0,0,0,0.55)] [z-index:calc(3-var(--i))] transition-transform duration-450 ease-stk32 group-hover:[transform:translateY(calc(var(--i)*-58px))] motion-reduce:transition-none" style="--i:0">
          <span class="text-[0.68rem] tracking-[0.12em] uppercase text-white/85">Organic</span>
          <b class="mt-0.5 block text-[0.95rem]">62%</b>
        </div>
        <div class="pointer-events-none absolute inset-x-0 h-13.5 rounded-xl bg-stk32-m2 px-3 py-2 text-[0.72rem] text-white shadow-[0_8px_18px_rgba(0,0,0,0.55)] [z-index:calc(3-var(--i))] transition-transform duration-450 ease-stk32 group-hover:[transform:translateY(calc(var(--i)*-58px))] motion-reduce:transition-none" style="--i:1">
          <span class="text-[0.68rem] tracking-[0.12em] uppercase text-white/85">Paid</span>
          <b class="mt-0.5 block text-[0.95rem]">24%</b>
        </div>
        <div class="pointer-events-none absolute inset-x-0 h-13.5 rounded-xl bg-stk32-m3 px-3 py-2 text-[0.72rem] text-white shadow-[0_8px_18px_rgba(0,0,0,0.55)] [z-index:calc(3-var(--i))] transition-transform duration-450 ease-stk32 group-hover:[transform:translateY(calc(var(--i)*-58px))] motion-reduce:transition-none" style="--i:2">
          <span class="text-[0.68rem] tracking-[0.12em] uppercase text-white/85">Referral</span>
          <b class="mt-0.5 block text-[0.95rem]">14%</b>
        </div>
      </div>
    </div>
    <div class="relative col-span-2 overflow-hidden rounded-[18px] border border-stk32-line bg-stk32-tile p-4 transition-colors duration-300 hover:border-stk32-lineh">
      <div class="pointer-events-none absolute -right-8 -top-8 size-24 rounded-full bg-stk32-good opacity-20 blur-2xl" aria-hidden="true"></div>
      <span class="text-[0.68rem] tracking-[0.12em] uppercase text-stk32-lbl">Revenue</span>
      <div class="mt-1 text-[1.6rem] font-bold text-stk32-val">$48.2k <small class="text-[0.8rem] font-semibold text-stk32-good">+12%</small></div>
      <div class="mt-2 flex h-8 items-end gap-1.5" aria-hidden="true">
        <span class="w-2 rounded-t bg-stk32-bar" style="height:40%"></span>
        <span class="w-2 rounded-t bg-stk32-bar" style="height:55%"></span>
        <span class="w-2 rounded-t bg-stk32-bar" style="height:45%"></span>
        <span class="w-2 rounded-t bg-stk32-bar" style="height:70%"></span>
        <span class="w-2 rounded-t bg-stk32-bar" style="height:60%"></span>
        <span class="w-2 rounded-t bg-stk32-bar" style="height:85%"></span>
        <span class="w-2 rounded-t bg-stk32-good" style="height:100%"></span>
      </div>
    </div>
    <div class="relative overflow-hidden rounded-[18px] border border-stk32-line bg-stk32-tile p-4 transition-colors duration-300 hover:border-stk32-lineh">
      <span class="text-[0.68rem] tracking-[0.12em] uppercase text-stk32-lbl">Users</span>
      <div class="mt-1 text-[1.6rem] font-bold text-stk32-val">9.1k</div>
    </div>
    <div class="relative overflow-hidden rounded-[18px] border border-stk32-line bg-stk32-tile p-4 transition-colors duration-300 hover:border-stk32-lineh">
      <span class="text-[0.68rem] tracking-[0.12em] uppercase text-stk32-lbl">Churn</span>
      <div class="mt-1 text-[1.6rem] font-bold text-stk32-bad">1.8%</div>
    </div>
    <div class="relative overflow-hidden rounded-[18px] border border-stk32-line bg-stk32-tile p-4 transition-colors duration-300 hover:border-stk32-lineh">
      <div class="pointer-events-none absolute -left-8 -bottom-8 size-24 rounded-full bg-stk32-m1 opacity-25 blur-2xl" aria-hidden="true"></div>
      <span class="text-[0.68rem] tracking-[0.12em] uppercase text-stk32-lbl">NPS</span>
      <div class="mt-1 text-[1.6rem] font-bold text-stk32-val">72</div>
    </div>
  </div>
</section>
```
## CSS
```css
@import "tailwindcss";

@theme {
  --color-stk32-bg: #0e0f13;
  --color-stk32-bg: oklch(0.17 0.008 275);
  --color-stk32-tile: #191b22;
  --color-stk32-tile: oklch(0.23 0.012 275);
  --color-stk32-line: #262934;
  --color-stk32-line: oklch(0.30 0.014 275);
  --color-stk32-lineh: #3a4050;
  --color-stk32-lineh: oklch(0.40 0.018 275);
  --color-stk32-lbl: #8a90a0;
  --color-stk32-lbl: oklch(0.64 0.016 275);
  --color-stk32-val: #f3f4f6;
  --color-stk32-val: oklch(0.97 0.003 275);
  --color-stk32-bar: #4b5162;
  --color-stk32-bar: oklch(0.46 0.020 275);
  --color-stk32-good: #34d399;
  --color-stk32-good: oklch(0.78 0.15 165);
  --color-stk32-bad: #fca5a5;
  --color-stk32-bad: oklch(0.79 0.10 20);
  --color-stk32-m1: #818cf8;
  --color-stk32-m1: oklch(0.68 0.15 280);
  --color-stk32-m2: #f472b6;
  --color-stk32-m2: oklch(0.72 0.17 350);
  --color-stk32-m3: #2dd4bf;
  --color-stk32-m3: oklch(0.79 0.13 180);
  --font-stk32-sans: 'Geist', system-ui, sans-serif;
  --ease-stk32: cubic-bezier(0.3, 0.9, 0.3, 1);
}
```

How this works

Named areas are unnecessary here, and that is a real finding. A fixed 3×3 bento is fully described by a track list and two span utilities:

<div class="grid grid-cols-[repeat(3,118px)] grid-rows-[repeat(3,118px)] gap-3">
  <div class="row-span-2 …">channels</div>
  <div class="col-span-2 …">revenue</div>

Named areas earn their keep when the layout changes shape across breakpoints; for a fixed grid they add a naming layer with nothing behind it.

The nested stack needs one tile to break its own clipping. Every tile is overflow-hidden so glows stay inside — except the channels tile, which is overflow-visible and lifts to hover:z-20 so its fan can cross the cell boundary. Being able to see that exception on the element, rather than in a modifier class three rules away, is the practical gain.

The fan is the index pattern again. Each mini-card carries --i and moves by a multiple of it. Nothing about it is new — which is the point: after thirty demos the same three lines handle a fan, a stair, a tower and a pile.

Decorative data must say so. The sparkline is a row of divs with inline heights and the whole group is aria-hidden; the number beside it is the real content. A chart that means something needs a text equivalent, and one that does not should be silent.

Make it yours

  • Change the bento shape by editing the track lists and the span utilities — no area names to keep in sync.
  • Adjust the fan distance via the -58px multiplier in the mini-card transform.
  • Feed the sparkline real values by editing the inline heights, or swap it for an SVG path.
  • Recolour each tile's accent glow independently; the tile shell is shared.
  • Add a tile and the grid absorbs it — the layout has no fixed child count.

Gotchas — read before shipping

  • Set pointer-events-none on the decorative mini-cards, or they swallow the hover on the tile that is meant to be fanning them.
  • Only the fanning tile may be overflow-visible; leaving them all unclipped lets every glow bleed across the grid.
  • Raise z-index on the fanning tile too — overflow-visible alone still paints it under later siblings.
  • Test text contrast per tile. Dashboard tiles vary in luminance and one dim tile can quietly fail while the others pass.
  • Mark decorative charts aria-hidden. A bar row with no labels announced as a list of empty divs is worse than silence.
  • Bento layouts are strongly trend-coded; for an evergreen product a plainer grid ages better.

Browser support

ChromeSafariFirefoxEdge
111+16.4+128+111+

CSS Grid with explicit track lists and spans is universal (Chrome 57+, Safari 10.1+, 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…