36 Tailwind Stacked Cards
08 / 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 Tabbed Card Stack Bring to Front

A filing-cabinet deck where clicking a tab brings its card to the absolute front. The CSS version needs eight :nth-of-type pairings to connect radio n to tab n; the port throws all of them away by nesting each radio, tab and card together and using plain peer-checked:. Restructuring the markup is the port — and the result is shorter, flatter and far easier to extend.

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-08 w-full min-h-svh flex items-center justify-center px-5 py-15 font-stk08-sans bg-stk08-bg" aria-label="Tabbed card deck">
  <div class="relative w-[min(400px,100%)] h-75 pt-11">
    <div class="contents">
      <input class="peer sr-only" type="radio" name="stk-08" id="stk-08-1" checked>
      <label class="absolute top-0 left-[calc(var(--l)*25%)] z-5 flex h-10 w-[24%] items-center justify-center rounded-t-xl bg-stk08-c1 text-[13px] font-bold text-white cursor-pointer brightness-80 transition-[filter,transform] duration-250 hover:brightness-95 peer-checked:brightness-100 peer-checked:-translate-y-1 peer-focus-visible:outline-3 peer-focus-visible:outline-white peer-focus-visible:outline-offset-3 motion-reduce:transition-none" for="stk-08-1" style="--l:0">Overview</label>
      <article class="absolute inset-x-0 top-10 z-1 h-62.5 rounded-b-2xl rounded-tr-2xl bg-stk08-c1 p-7 text-white shadow-[0_26px_50px_-28px_rgba(0,0,0,0.7)] translate-y-6 scale-[0.94] transition-transform duration-450 ease-stk08 peer-checked:z-4 peer-checked:translate-y-0 peer-checked:scale-100 motion-reduce:transition-none">
        <h3 class="m-0 mb-3 text-2xl font-extrabold tracking-[-0.02em]">Overview</h3>
        <p class="m-0 max-w-[34ch] text-[15px] leading-relaxed">One deck, four surfaces. Click a tab and its card comes to the very front.</p>
      </article>
    </div>
    <div class="contents">
      <input class="peer sr-only" type="radio" name="stk-08" id="stk-08-2">
      <label class="absolute top-0 left-[calc(var(--l)*25%)] z-5 flex h-10 w-[24%] items-center justify-center rounded-t-xl bg-stk08-c2 text-[13px] font-bold text-white cursor-pointer brightness-80 transition-[filter,transform] duration-250 hover:brightness-95 peer-checked:brightness-100 peer-checked:-translate-y-1 peer-focus-visible:outline-3 peer-focus-visible:outline-white peer-focus-visible:outline-offset-3 motion-reduce:transition-none" for="stk-08-2" style="--l:1">Pricing</label>
      <article class="absolute inset-x-0 top-10 z-1 h-62.5 rounded-b-2xl rounded-tr-2xl bg-stk08-c2 p-7 text-white shadow-[0_26px_50px_-28px_rgba(0,0,0,0.7)] translate-y-6 scale-[0.94] transition-transform duration-450 ease-stk08 peer-checked:z-4 peer-checked:translate-y-0 peer-checked:scale-100 motion-reduce:transition-none">
        <h3 class="m-0 mb-3 text-2xl font-extrabold tracking-[-0.02em]">Pricing</h3>
        <p class="m-0 max-w-[34ch] text-[15px] leading-relaxed">Flat monthly tiers, no seats, cancel anytime. Start free, upgrade when it pays off.</p>
      </article>
    </div>
    <div class="contents">
      <input class="peer sr-only" type="radio" name="stk-08" id="stk-08-3">
      <label class="absolute top-0 left-[calc(var(--l)*25%)] z-5 flex h-10 w-[24%] items-center justify-center rounded-t-xl bg-stk08-c3 text-[13px] font-bold text-white cursor-pointer brightness-80 transition-[filter,transform] duration-250 hover:brightness-95 peer-checked:brightness-100 peer-checked:-translate-y-1 peer-focus-visible:outline-3 peer-focus-visible:outline-white peer-focus-visible:outline-offset-3 motion-reduce:transition-none" for="stk-08-3" style="--l:2">Docs</label>
      <article class="absolute inset-x-0 top-10 z-1 h-62.5 rounded-b-2xl rounded-tr-2xl bg-stk08-c3 p-7 text-white shadow-[0_26px_50px_-28px_rgba(0,0,0,0.7)] translate-y-6 scale-[0.94] transition-transform duration-450 ease-stk08 peer-checked:z-4 peer-checked:translate-y-0 peer-checked:scale-100 motion-reduce:transition-none">
        <h3 class="m-0 mb-3 text-2xl font-extrabold tracking-[-0.02em]">Docs</h3>
        <p class="m-0 max-w-[34ch] text-[15px] leading-relaxed">Copy-paste snippets, live playgrounds and a searchable API. Zero setup to try.</p>
      </article>
    </div>
    <div class="contents">
      <input class="peer sr-only" type="radio" name="stk-08" id="stk-08-4">
      <label class="absolute top-0 left-[calc(var(--l)*25%)] z-5 flex h-10 w-[24%] items-center justify-center rounded-t-xl bg-stk08-c4 text-[13px] font-bold text-white cursor-pointer brightness-80 transition-[filter,transform] duration-250 hover:brightness-95 peer-checked:brightness-100 peer-checked:-translate-y-1 peer-focus-visible:outline-3 peer-focus-visible:outline-white peer-focus-visible:outline-offset-3 motion-reduce:transition-none" for="stk-08-4" style="--l:3">Support</label>
      <article class="absolute inset-x-0 top-10 z-1 h-62.5 rounded-b-2xl rounded-tr-2xl bg-stk08-c4 p-7 text-white shadow-[0_26px_50px_-28px_rgba(0,0,0,0.7)] translate-y-6 scale-[0.94] transition-transform duration-450 ease-stk08 peer-checked:z-4 peer-checked:translate-y-0 peer-checked:scale-100 motion-reduce:transition-none">
        <h3 class="m-0 mb-3 text-2xl font-extrabold tracking-[-0.02em]">Support</h3>
        <p class="m-0 max-w-[34ch] text-[15px] leading-relaxed">Real humans, weekday chat, and a status page that actually stays current.</p>
      </article>
    </div>
  </div>
</section>
@import "tailwindcss";

@theme {
  --color-stk08-bg: #20222c;
  --color-stk08-bg: oklch(0.26 0.012 275);
  --color-stk08-c1: #d9694f;
  --color-stk08-c1: oklch(0.62 0.17 25);
  --color-stk08-c2: #3fa774;
  --color-stk08-c2: oklch(0.62 0.16 145);
  --color-stk08-c3: #4a8fd4;
  --color-stk08-c3: oklch(0.60 0.15 235);
  --color-stk08-c4: #9a6fd0;
  --color-stk08-c4: oklch(0.60 0.16 300);
  --font-stk08-sans: 'Archivo', system-ui, sans-serif;
  --ease-stk08: 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-stk08-bg: #20222c;
  --color-stk08-bg: oklch(0.26 0.012 275);
  --color-stk08-c1: #d9694f;
  --color-stk08-c1: oklch(0.62 0.17 25);
  --color-stk08-c2: #3fa774;
  --color-stk08-c2: oklch(0.62 0.16 145);
  --color-stk08-c3: #4a8fd4;
  --color-stk08-c3: oklch(0.60 0.15 235);
  --color-stk08-c4: #9a6fd0;
  --color-stk08-c4: oklch(0.60 0.16 300);
  --font-stk08-sans: 'Archivo', system-ui, sans-serif;
  --ease-stk08: 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,700;75..125,800&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 :nth-of-type(n):checked ~ :nth-of-type(n) selectors vanish. Nesting each radio with its own tab and card makes plain peer-checked: sufficient — the clearest case in the collection where the port improves the markup rather than merely translating it.
  • display:contents on each group (Tailwind's contents) keeps the new wrapper out of the layout, so the absolutely-positioned tabs and cards still resolve against the deck.
  • The four tab left rules become left-[calc(var(--l)*25%)] reading a per-tab index.
  • Colour is declared once per group and shared by the tab and the card, so a recolour cannot leave the two out of sync.
  • The radios stay sr-only and therefore focusable, which is what makes native arrow-key tab switching work with no script.
  • The stylesheet is @theme only — a four-panel tab deck with zero custom selectors and zero JavaScript.
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 Tabbed Card Stack Bring to Front
Source: https://codefronts.com/components/tailwind-stacked-cards/tailwind-tabbed-card-stack-bring-to-front/

A filing-cabinet deck where clicking a tab brings its card to the absolute front. The CSS version needs eight :nth-of-type pairings to connect radio n to tab n; the port throws all of them away by nesting each radio, tab and card together and using plain peer-checked:. Restructuring the markup is the port &mdash; and the result is shorter, flatter and far easier to extend.
## HTML
```html
<section class="stk-08 w-full min-h-svh flex items-center justify-center px-5 py-15 font-stk08-sans bg-stk08-bg" aria-label="Tabbed card deck">
  <div class="relative w-[min(400px,100%)] h-75 pt-11">
    <div class="contents">
      <input class="peer sr-only" type="radio" name="stk-08" id="stk-08-1" checked>
      <label class="absolute top-0 left-[calc(var(--l)*25%)] z-5 flex h-10 w-[24%] items-center justify-center rounded-t-xl bg-stk08-c1 text-[13px] font-bold text-white cursor-pointer brightness-80 transition-[filter,transform] duration-250 hover:brightness-95 peer-checked:brightness-100 peer-checked:-translate-y-1 peer-focus-visible:outline-3 peer-focus-visible:outline-white peer-focus-visible:outline-offset-3 motion-reduce:transition-none" for="stk-08-1" style="--l:0">Overview</label>
      <article class="absolute inset-x-0 top-10 z-1 h-62.5 rounded-b-2xl rounded-tr-2xl bg-stk08-c1 p-7 text-white shadow-[0_26px_50px_-28px_rgba(0,0,0,0.7)] translate-y-6 scale-[0.94] transition-transform duration-450 ease-stk08 peer-checked:z-4 peer-checked:translate-y-0 peer-checked:scale-100 motion-reduce:transition-none">
        <h3 class="m-0 mb-3 text-2xl font-extrabold tracking-[-0.02em]">Overview</h3>
        <p class="m-0 max-w-[34ch] text-[15px] leading-relaxed">One deck, four surfaces. Click a tab and its card comes to the very front.</p>
      </article>
    </div>
    <div class="contents">
      <input class="peer sr-only" type="radio" name="stk-08" id="stk-08-2">
      <label class="absolute top-0 left-[calc(var(--l)*25%)] z-5 flex h-10 w-[24%] items-center justify-center rounded-t-xl bg-stk08-c2 text-[13px] font-bold text-white cursor-pointer brightness-80 transition-[filter,transform] duration-250 hover:brightness-95 peer-checked:brightness-100 peer-checked:-translate-y-1 peer-focus-visible:outline-3 peer-focus-visible:outline-white peer-focus-visible:outline-offset-3 motion-reduce:transition-none" for="stk-08-2" style="--l:1">Pricing</label>
      <article class="absolute inset-x-0 top-10 z-1 h-62.5 rounded-b-2xl rounded-tr-2xl bg-stk08-c2 p-7 text-white shadow-[0_26px_50px_-28px_rgba(0,0,0,0.7)] translate-y-6 scale-[0.94] transition-transform duration-450 ease-stk08 peer-checked:z-4 peer-checked:translate-y-0 peer-checked:scale-100 motion-reduce:transition-none">
        <h3 class="m-0 mb-3 text-2xl font-extrabold tracking-[-0.02em]">Pricing</h3>
        <p class="m-0 max-w-[34ch] text-[15px] leading-relaxed">Flat monthly tiers, no seats, cancel anytime. Start free, upgrade when it pays off.</p>
      </article>
    </div>
    <div class="contents">
      <input class="peer sr-only" type="radio" name="stk-08" id="stk-08-3">
      <label class="absolute top-0 left-[calc(var(--l)*25%)] z-5 flex h-10 w-[24%] items-center justify-center rounded-t-xl bg-stk08-c3 text-[13px] font-bold text-white cursor-pointer brightness-80 transition-[filter,transform] duration-250 hover:brightness-95 peer-checked:brightness-100 peer-checked:-translate-y-1 peer-focus-visible:outline-3 peer-focus-visible:outline-white peer-focus-visible:outline-offset-3 motion-reduce:transition-none" for="stk-08-3" style="--l:2">Docs</label>
      <article class="absolute inset-x-0 top-10 z-1 h-62.5 rounded-b-2xl rounded-tr-2xl bg-stk08-c3 p-7 text-white shadow-[0_26px_50px_-28px_rgba(0,0,0,0.7)] translate-y-6 scale-[0.94] transition-transform duration-450 ease-stk08 peer-checked:z-4 peer-checked:translate-y-0 peer-checked:scale-100 motion-reduce:transition-none">
        <h3 class="m-0 mb-3 text-2xl font-extrabold tracking-[-0.02em]">Docs</h3>
        <p class="m-0 max-w-[34ch] text-[15px] leading-relaxed">Copy-paste snippets, live playgrounds and a searchable API. Zero setup to try.</p>
      </article>
    </div>
    <div class="contents">
      <input class="peer sr-only" type="radio" name="stk-08" id="stk-08-4">
      <label class="absolute top-0 left-[calc(var(--l)*25%)] z-5 flex h-10 w-[24%] items-center justify-center rounded-t-xl bg-stk08-c4 text-[13px] font-bold text-white cursor-pointer brightness-80 transition-[filter,transform] duration-250 hover:brightness-95 peer-checked:brightness-100 peer-checked:-translate-y-1 peer-focus-visible:outline-3 peer-focus-visible:outline-white peer-focus-visible:outline-offset-3 motion-reduce:transition-none" for="stk-08-4" style="--l:3">Support</label>
      <article class="absolute inset-x-0 top-10 z-1 h-62.5 rounded-b-2xl rounded-tr-2xl bg-stk08-c4 p-7 text-white shadow-[0_26px_50px_-28px_rgba(0,0,0,0.7)] translate-y-6 scale-[0.94] transition-transform duration-450 ease-stk08 peer-checked:z-4 peer-checked:translate-y-0 peer-checked:scale-100 motion-reduce:transition-none">
        <h3 class="m-0 mb-3 text-2xl font-extrabold tracking-[-0.02em]">Support</h3>
        <p class="m-0 max-w-[34ch] text-[15px] leading-relaxed">Real humans, weekday chat, and a status page that actually stays current.</p>
      </article>
    </div>
  </div>
</section>
```
## CSS
```css
@import "tailwindcss";

@theme {
  --color-stk08-bg: #20222c;
  --color-stk08-bg: oklch(0.26 0.012 275);
  --color-stk08-c1: #d9694f;
  --color-stk08-c1: oklch(0.62 0.17 25);
  --color-stk08-c2: #3fa774;
  --color-stk08-c2: oklch(0.62 0.16 145);
  --color-stk08-c3: #4a8fd4;
  --color-stk08-c3: oklch(0.60 0.15 235);
  --color-stk08-c4: #9a6fd0;
  --color-stk08-c4: oklch(0.60 0.16 300);
  --font-stk08-sans: 'Archivo', system-ui, sans-serif;
  --ease-stk08: cubic-bezier(0.3, 0.9, 0.3, 1);
}
```

How this works

The port is a restructure, and it is worth it. The CSS version puts four radios first, then four labels, then four cards, and pays for it with eight selectors like .r:nth-of-type(2):checked ~ .tab:nth-of-type(2). Utilities cannot express positional pairing at all — so instead each unit becomes self-contained:

<div>
  <input class="peer sr-only" type="radio" name="stk-08" id="stk-08-2">
  <label class="… peer-checked:brightness-100" for="stk-08-2">Pricing</label>
  <article class="… peer-checked:z-4 peer-checked:scale-100">…</article>
</div>

Eight fragile selectors become two variants, and adding a fifth tab is copying one block rather than editing four rule lists.

The tab strip is arithmetic, not positions. Each tab carries --l and sits at left-[calc(var(--l)*25%)], so the strip stays evenly divided at any width and a fifth tab only needs its index and a 20% step.

Radios give you keyboard tabs for free. A same-named radio group already answers arrow keys, so this deck needs no roving tabindex and no keydown handler — provided the inputs are sr-only rather than hidden.

Resting cards must not cover the tabs. Unchecked cards sit translate-y-6 scale-[0.94] below the strip; the front card covers their bodies but never their handles, which is what makes the metaphor legible.

Make it yours

  • Add a tab by copying one block, giving it the next --l and changing the 25% step to match the new count.
  • Change the resting fan with the unchecked translate-y-6 scale-[0.94].
  • Recolour a tab and its card together — both read the same bg-stk08-* token, so they cannot drift apart.
  • Set the initially open card by moving the checked attribute.
  • Widen the tabs by editing w-[24%]; leave a sliver of gap or adjacent tabs become one target.

Gotchas — read before shipping

  • Nest each radio with its own tab and card. Left as three flat lists, peer-checked: reaches the wrong elements and there is no variant that can fix it.
  • sr-only, never hidden. display:none takes the radios out of the tab order and the arrow-key switching disappears with them.
  • Space the tabs so every one stays clickable while the cards overlap; the front card is allowed to cover bodies, not handles.
  • Give the deck pt-11 so the tab strip has its own band above the cards.
  • left-[calc(var(--l)*25%)] must be typed closed-up — a space inside an arbitrary value ends the class.
  • Keep the tab label text at font-bold over the mid-tone fill; a dimmed inactive tab still has to clear 4.5:1.

Browser support

ChromeSafariFirefoxEdge
111+16.4+128+111+

Radio :checked with sibling combinators and transforms is 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

Search CodeFronts

Loading…