08 / 36
All 36 in 36 Tailwind Stacked Cards
- 01Tailwind Scroll-Driven Scaling Card Stack
- 02Tailwind Swipe Card Deck Drag to Dismiss
- 03Tailwind Glassmorphism Testimonial Card Stack
- 04Tailwind Stacked Cards Expand Accordion on Click
- 05Tailwind Fan Out Photo Stack on Hover
- 06Tailwind 3D Perspective Tilt Card Stack
- 07Tailwind Multi Step Form Card Stack
- 08Tailwind Tabbed Card Stack Bring to Front
- 09Tailwind Click to Front Stacked Cards Cycle
- 10Tailwind Classic Card Deck Stack Shadow
- 11Tailwind Fan Spread Hand of Cards
- 12Tailwind Polaroid Photo Stack Scattered Rotate
- 13Tailwind Staircase Offset Stacked Cards Cascade
- 14Tailwind Cards Spread Out Horizontally on Hover
- 15Tailwind Stacked Cards Lift on Hover Sibling Push
- 16Tailwind Accordion Stacked Cards Slide Out Menu
- 17Tailwind Shuffle Cards Animation Loop Deck
- 18Tailwind File Folder Tab Stacked Cards
- 19Tailwind Scattered Photos Pinch to Centre on Hover
- 20Tailwind Mobile Swipe Card Stack Translate3d
- 21Tailwind Single Accordion Card Nested Layers
- 22Tailwind Isometric Tower Stacked Cards 3D Column
- 23Tailwind 3D Flip Card Stack Reveal Back
- 24Tailwind Card Stack Tilt on Hover Quadrant
- 25Tailwind Notification Stack Pile Dismiss
- 26Tailwind Receipt Roll Unroll Stacked Items
- 27Tailwind Scratch Card Reveal Canvas Mask
- 28Tailwind Stacked Cards Hover Reveal Spread
- 29Tailwind Scroll Activated Sticky Stacking Cards
- 30Tailwind Stacked Testimonial Slider Radio
- 31Tailwind Isometric Overlapping Stacked Cards
- 32Tailwind Bento Grid Stacked Cards Hover Fan
- 33Tailwind Perspective Card Deck Depth Tunnel
- 34Tailwind Peel Back Corner Card Reveal
- 35Tailwind Timeline Stacked Milestone Cards
- 36Tailwind Spiral Tower Rotating 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 — and the result is shorter, flatter and far easier to extend.
Untitled UI Pro: 5,000+ React + Tailwind CSS v4 components · from $349 one-time
Untitled UI React · Affiliate link
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><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);
}@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.
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
<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.
npm install tailwindcss @tailwindcss/vite
npm install tailwindcss @tailwindcss/vite// vite.config.js ("type": "module" in package.json)
import { defineConfig } from 'vite'
import tailwindcss from '@tailwindcss/vite'
export default defineConfig({
plugins: [tailwindcss()],
})// vite.config.js ("type": "module" in package.json)
import { defineConfig } from 'vite'
import tailwindcss from '@tailwindcss/vite'
export default defineConfig({
plugins: [tailwindcss()],
})Any v4 setup works — Vite, PostCSS or the CLI. Nothing in this demo is bundler-specific.
@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);
}@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);
}<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">
<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 insetup, not as an@importinside the stylesheet. Tailwind emits user@importrules after its own@layerblocks, and a late@importis 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 plainpeer-checked:sufficient — the clearest case in the collection where the port improves the markup rather than merely translating it. display:contentson each group (Tailwind'scontents) keeps the new wrapper out of the layout, so the absolutely-positioned tabs and cards still resolve against the deck.- The four tab
leftrules becomeleft-[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-onlyand therefore focusable, which is what makes native arrow-key tab switching work with no script. - The stylesheet is
@themeonly — a four-panel tab deck with zero custom selectors and zero JavaScript.
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 — 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);
}
```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 — 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
--land changing the25%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
checkedattribute. - 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, neverhidden.display:nonetakes 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-11so 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-boldover the mid-tone fill; a dimmed inactive tab still has to clear 4.5:1.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 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.