34 / 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 Peel Back Corner Card Reveal
A sticker-card that curls off its stack from the top-right corner, revealing the vivid layers beneath. The port swaps animated clip-path for a rotate-scale-and-radius peel, which is the better engineering call: clip-path only interpolates between polygons with matching vertex counts, while a transform plus one asymmetric border-radius gets the same read and stays on the compositor.
Untitled UI Pro: 5,000+ React + Tailwind CSS v4 components · from $349 one-time
Untitled UI React · Affiliate link
The code
<section class="stk-34 grid w-full min-h-svh place-items-center px-5 py-15 font-stk34-sans bg-stk34-bg" aria-label="Peel-back card stack">
<div class="group relative h-85 w-65">
<div class="absolute inset-0 z-1 flex flex-col justify-end overflow-hidden rounded-[22px] bg-linear-[150deg,var(--color-stk34-c3a),var(--color-stk34-c3b)] p-7.5 text-stk34-deep shadow-[0_12px_26px_rgba(0,0,0,0.18)]">
<h3 class="m-0 font-stk34-display text-3xl font-extrabold leading-none">Layer C</h3>
<p class="m-0 mt-1.5 opacity-85">Bottom of the stack</p>
</div>
<div class="absolute inset-0 z-2 flex flex-col justify-end overflow-hidden rounded-[22px] bg-linear-[150deg,var(--color-stk34-c2a),var(--color-stk34-c2b)] p-7.5 text-white shadow-[0_12px_26px_rgba(0,0,0,0.18)] transition-transform duration-700 ease-stk34 group-hover:-translate-y-2.5 motion-reduce:transition-none motion-reduce:translate-none!">
<h3 class="m-0 font-stk34-display text-3xl font-extrabold leading-none">Layer B</h3>
<p class="m-0 mt-1.5 opacity-85">The middle ground</p>
</div>
<div class="absolute inset-0 z-3 flex cursor-pointer flex-col justify-end overflow-hidden rounded-[22px] bg-linear-[150deg,var(--color-stk34-c1a),var(--color-stk34-c1b)] p-7.5 text-white shadow-[0_12px_26px_rgba(0,0,0,0.18)] [transform-origin:top_right] transition-[transform,border-radius,box-shadow,opacity] duration-700 ease-stk34 group-hover:rounded-bl-[90px] group-hover:shadow-[-20px_20px_40px_rgba(0,0,0,0.3)] group-hover:[transform:rotate(-14deg)_translate(-30px,-30px)_scale(0.78)] motion-reduce:transition-opacity motion-reduce:rotate-none! motion-reduce:translate-none! motion-reduce:scale-100! motion-reduce:group-hover:opacity-0">
<h3 class="m-0 font-stk34-display text-3xl font-extrabold leading-none">Peel me</h3>
<p class="m-0 mt-1.5 opacity-85">Hover to lift the top</p>
</div>
</div>
</section><section class="stk-34 grid w-full min-h-svh place-items-center px-5 py-15 font-stk34-sans bg-stk34-bg" aria-label="Peel-back card stack">
<div class="group relative h-85 w-65">
<div class="absolute inset-0 z-1 flex flex-col justify-end overflow-hidden rounded-[22px] bg-linear-[150deg,var(--color-stk34-c3a),var(--color-stk34-c3b)] p-7.5 text-stk34-deep shadow-[0_12px_26px_rgba(0,0,0,0.18)]">
<h3 class="m-0 font-stk34-display text-3xl font-extrabold leading-none">Layer C</h3>
<p class="m-0 mt-1.5 opacity-85">Bottom of the stack</p>
</div>
<div class="absolute inset-0 z-2 flex flex-col justify-end overflow-hidden rounded-[22px] bg-linear-[150deg,var(--color-stk34-c2a),var(--color-stk34-c2b)] p-7.5 text-white shadow-[0_12px_26px_rgba(0,0,0,0.18)] transition-transform duration-700 ease-stk34 group-hover:-translate-y-2.5 motion-reduce:transition-none motion-reduce:translate-none!">
<h3 class="m-0 font-stk34-display text-3xl font-extrabold leading-none">Layer B</h3>
<p class="m-0 mt-1.5 opacity-85">The middle ground</p>
</div>
<div class="absolute inset-0 z-3 flex cursor-pointer flex-col justify-end overflow-hidden rounded-[22px] bg-linear-[150deg,var(--color-stk34-c1a),var(--color-stk34-c1b)] p-7.5 text-white shadow-[0_12px_26px_rgba(0,0,0,0.18)] [transform-origin:top_right] transition-[transform,border-radius,box-shadow,opacity] duration-700 ease-stk34 group-hover:rounded-bl-[90px] group-hover:shadow-[-20px_20px_40px_rgba(0,0,0,0.3)] group-hover:[transform:rotate(-14deg)_translate(-30px,-30px)_scale(0.78)] motion-reduce:transition-opacity motion-reduce:rotate-none! motion-reduce:translate-none! motion-reduce:scale-100! motion-reduce:group-hover:opacity-0">
<h3 class="m-0 font-stk34-display text-3xl font-extrabold leading-none">Peel me</h3>
<p class="m-0 mt-1.5 opacity-85">Hover to lift the top</p>
</div>
</div>
</section>@import "tailwindcss";
@theme {
--color-stk34-bg: #ececec;
--color-stk34-bg: oklch(0.94 0.001 0);
--color-stk34-deep: #044d33;
--color-stk34-deep: oklch(0.35 0.080 165);
--color-stk34-c1a: #ff6a3d;
--color-stk34-c1b: #f9484a;
--color-stk34-c2a: #1fa2ff;
--color-stk34-c2b: #12d8fa;
--color-stk34-c3a: #43e97b;
--color-stk34-c3b: #38f9d7;
--font-stk34-sans: 'Outfit', system-ui, sans-serif;
--font-stk34-display: 'Bricolage Grotesque', system-ui, sans-serif;
--ease-stk34: cubic-bezier(0.2, 0.8, 0.2, 1);
}@import "tailwindcss";
@theme {
--color-stk34-bg: #ececec;
--color-stk34-bg: oklch(0.94 0.001 0);
--color-stk34-deep: #044d33;
--color-stk34-deep: oklch(0.35 0.080 165);
--color-stk34-c1a: #ff6a3d;
--color-stk34-c1b: #f9484a;
--color-stk34-c2a: #1fa2ff;
--color-stk34-c2b: #12d8fa;
--color-stk34-c3a: #43e97b;
--color-stk34-c3b: #38f9d7;
--font-stk34-sans: 'Outfit', system-ui, sans-serif;
--font-stk34-display: 'Bricolage Grotesque', system-ui, sans-serif;
--ease-stk34: cubic-bezier(0.2, 0.8, 0.2, 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-stk34-bg: #ececec;
--color-stk34-bg: oklch(0.94 0.001 0);
--color-stk34-deep: #044d33;
--color-stk34-deep: oklch(0.35 0.080 165);
--color-stk34-c1a: #ff6a3d;
--color-stk34-c1b: #f9484a;
--color-stk34-c2a: #1fa2ff;
--color-stk34-c2b: #12d8fa;
--color-stk34-c3a: #43e97b;
--color-stk34-c3b: #38f9d7;
--font-stk34-sans: 'Outfit', system-ui, sans-serif;
--font-stk34-display: 'Bricolage Grotesque', system-ui, sans-serif;
--ease-stk34: cubic-bezier(0.2, 0.8, 0.2, 1);
}@import "tailwindcss";
@theme {
--color-stk34-bg: #ececec;
--color-stk34-bg: oklch(0.94 0.001 0);
--color-stk34-deep: #044d33;
--color-stk34-deep: oklch(0.35 0.080 165);
--color-stk34-c1a: #ff6a3d;
--color-stk34-c1b: #f9484a;
--color-stk34-c2a: #1fa2ff;
--color-stk34-c2b: #12d8fa;
--color-stk34-c3a: #43e97b;
--color-stk34-c3b: #38f9d7;
--font-stk34-sans: 'Outfit', system-ui, sans-serif;
--font-stk34-display: 'Bricolage Grotesque', system-ui, sans-serif;
--ease-stk34: cubic-bezier(0.2, 0.8, 0.2, 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=Bricolage+Grotesque:wght@700;800&family=Outfit:wght@400&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=Bricolage+Grotesque:wght@700;800&family=Outfit:wght@400&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. - The port deliberately drops animated
clip-path: polygon interpolation requires matching vertex counts, and a transform plus one asymmetric radius gets the same read on the compositor with fewer failure modes. [transform-origin:top_right]is the declaration that turns a slide into a peel, and having it next to the transform makes that obvious.group-hover:rounded-bl-[90px]is doing the shape work — one radius, reliably interpolated, instead of a polygon with hand-matched vertices.- The hover shadow is directional (
-20px 20px), which is what makes the lifted corner read as casting a fold shadow rather than glowing. - The middle layer's small
-translate-y-2.5adds parallax, so the reveal feels like two objects rather than one card moving over a picture. - Reduced motion swaps the peel for a fade using three
!overrides — an off-origin rotate-and-scale is exactly the profile to remove rather than slow.
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 Peel Back Corner Card Reveal
Source: https://codefronts.com/components/tailwind-stacked-cards/tailwind-peel-back-corner-card-reveal/
A sticker-card that curls off its stack from the top-right corner, revealing the vivid layers beneath. The port swaps animated clip-path for a rotate-scale-and-radius peel, which is the better engineering call: clip-path only interpolates between polygons with matching vertex counts, while a transform plus one asymmetric border-radius gets the same read and stays on the compositor.
## HTML
```html
<section class="stk-34 grid w-full min-h-svh place-items-center px-5 py-15 font-stk34-sans bg-stk34-bg" aria-label="Peel-back card stack">
<div class="group relative h-85 w-65">
<div class="absolute inset-0 z-1 flex flex-col justify-end overflow-hidden rounded-[22px] bg-linear-[150deg,var(--color-stk34-c3a),var(--color-stk34-c3b)] p-7.5 text-stk34-deep shadow-[0_12px_26px_rgba(0,0,0,0.18)]">
<h3 class="m-0 font-stk34-display text-3xl font-extrabold leading-none">Layer C</h3>
<p class="m-0 mt-1.5 opacity-85">Bottom of the stack</p>
</div>
<div class="absolute inset-0 z-2 flex flex-col justify-end overflow-hidden rounded-[22px] bg-linear-[150deg,var(--color-stk34-c2a),var(--color-stk34-c2b)] p-7.5 text-white shadow-[0_12px_26px_rgba(0,0,0,0.18)] transition-transform duration-700 ease-stk34 group-hover:-translate-y-2.5 motion-reduce:transition-none motion-reduce:translate-none!">
<h3 class="m-0 font-stk34-display text-3xl font-extrabold leading-none">Layer B</h3>
<p class="m-0 mt-1.5 opacity-85">The middle ground</p>
</div>
<div class="absolute inset-0 z-3 flex cursor-pointer flex-col justify-end overflow-hidden rounded-[22px] bg-linear-[150deg,var(--color-stk34-c1a),var(--color-stk34-c1b)] p-7.5 text-white shadow-[0_12px_26px_rgba(0,0,0,0.18)] [transform-origin:top_right] transition-[transform,border-radius,box-shadow,opacity] duration-700 ease-stk34 group-hover:rounded-bl-[90px] group-hover:shadow-[-20px_20px_40px_rgba(0,0,0,0.3)] group-hover:[transform:rotate(-14deg)_translate(-30px,-30px)_scale(0.78)] motion-reduce:transition-opacity motion-reduce:rotate-none! motion-reduce:translate-none! motion-reduce:scale-100! motion-reduce:group-hover:opacity-0">
<h3 class="m-0 font-stk34-display text-3xl font-extrabold leading-none">Peel me</h3>
<p class="m-0 mt-1.5 opacity-85">Hover to lift the top</p>
</div>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-stk34-bg: #ececec;
--color-stk34-bg: oklch(0.94 0.001 0);
--color-stk34-deep: #044d33;
--color-stk34-deep: oklch(0.35 0.080 165);
--color-stk34-c1a: #ff6a3d;
--color-stk34-c1b: #f9484a;
--color-stk34-c2a: #1fa2ff;
--color-stk34-c2b: #12d8fa;
--color-stk34-c3a: #43e97b;
--color-stk34-c3b: #38f9d7;
--font-stk34-sans: 'Outfit', system-ui, sans-serif;
--font-stk34-display: 'Bricolage Grotesque', system-ui, sans-serif;
--ease-stk34: cubic-bezier(0.2, 0.8, 0.2, 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 Peel Back Corner Card Reveal
Source: https://codefronts.com/components/tailwind-stacked-cards/tailwind-peel-back-corner-card-reveal/
A sticker-card that curls off its stack from the top-right corner, revealing the vivid layers beneath. The port swaps animated clip-path for a rotate-scale-and-radius peel, which is the better engineering call: clip-path only interpolates between polygons with matching vertex counts, while a transform plus one asymmetric border-radius gets the same read and stays on the compositor.
## HTML
```html
<section class="stk-34 grid w-full min-h-svh place-items-center px-5 py-15 font-stk34-sans bg-stk34-bg" aria-label="Peel-back card stack">
<div class="group relative h-85 w-65">
<div class="absolute inset-0 z-1 flex flex-col justify-end overflow-hidden rounded-[22px] bg-linear-[150deg,var(--color-stk34-c3a),var(--color-stk34-c3b)] p-7.5 text-stk34-deep shadow-[0_12px_26px_rgba(0,0,0,0.18)]">
<h3 class="m-0 font-stk34-display text-3xl font-extrabold leading-none">Layer C</h3>
<p class="m-0 mt-1.5 opacity-85">Bottom of the stack</p>
</div>
<div class="absolute inset-0 z-2 flex flex-col justify-end overflow-hidden rounded-[22px] bg-linear-[150deg,var(--color-stk34-c2a),var(--color-stk34-c2b)] p-7.5 text-white shadow-[0_12px_26px_rgba(0,0,0,0.18)] transition-transform duration-700 ease-stk34 group-hover:-translate-y-2.5 motion-reduce:transition-none motion-reduce:translate-none!">
<h3 class="m-0 font-stk34-display text-3xl font-extrabold leading-none">Layer B</h3>
<p class="m-0 mt-1.5 opacity-85">The middle ground</p>
</div>
<div class="absolute inset-0 z-3 flex cursor-pointer flex-col justify-end overflow-hidden rounded-[22px] bg-linear-[150deg,var(--color-stk34-c1a),var(--color-stk34-c1b)] p-7.5 text-white shadow-[0_12px_26px_rgba(0,0,0,0.18)] [transform-origin:top_right] transition-[transform,border-radius,box-shadow,opacity] duration-700 ease-stk34 group-hover:rounded-bl-[90px] group-hover:shadow-[-20px_20px_40px_rgba(0,0,0,0.3)] group-hover:[transform:rotate(-14deg)_translate(-30px,-30px)_scale(0.78)] motion-reduce:transition-opacity motion-reduce:rotate-none! motion-reduce:translate-none! motion-reduce:scale-100! motion-reduce:group-hover:opacity-0">
<h3 class="m-0 font-stk34-display text-3xl font-extrabold leading-none">Peel me</h3>
<p class="m-0 mt-1.5 opacity-85">Hover to lift the top</p>
</div>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-stk34-bg: #ececec;
--color-stk34-bg: oklch(0.94 0.001 0);
--color-stk34-deep: #044d33;
--color-stk34-deep: oklch(0.35 0.080 165);
--color-stk34-c1a: #ff6a3d;
--color-stk34-c1b: #f9484a;
--color-stk34-c2a: #1fa2ff;
--color-stk34-c2b: #12d8fa;
--color-stk34-c3a: #43e97b;
--color-stk34-c3b: #38f9d7;
--font-stk34-sans: 'Outfit', system-ui, sans-serif;
--font-stk34-display: 'Bricolage Grotesque', system-ui, sans-serif;
--ease-stk34: cubic-bezier(0.2, 0.8, 0.2, 1);
}
```How this works
Why not clip-path. The classic implementation animates a polygon(), which interpolates only when both states have the same number of vertices — add or remove one and the animation snaps instead of tweening. It is also a paint-level property. The transform version:
[transform-origin:top_right]
group-hover:[transform:rotate(-14deg)_translate(-30px,-30px)_scale(0.78)]
group-hover:rounded-bl-[90px]gives the same physical read — a corner lifting toward you — from a compositor-only transform plus one radius. Fewer failure modes, cheaper, and legible in the class list.
The origin is the peel. top right means the rotation pivots at the corner being lifted, so the card swings away from that point like a label coming off its backing. With the default centre origin the same numbers just move the whole card.
What is underneath has to be worth revealing. A peel that exposes an empty gradient reads as a broken card. Each layer here carries a real label; in production this is where a discount code, a badge or the next step goes.
Reduced motion gets a reveal, not a slow peel. The curl is rotation and scale around an off-centre origin — exactly the profile that causes discomfort — so under motion-reduce: the top card simply fades and the layer beneath is visible.
Make it yours
- Move the peel to another corner by changing
[transform-origin:top_right], the translate signs and whichrounded-*corner grows. - Tune the peel size with the
scale(0.78)and the90pxradius — a smaller pair reads as a sticker lift, a larger one as a dog-eared postcard. - Rebrand each layer through its own gradient token pair.
- Add a label (SALE, NEW) inside the revealed area with a
group-hover:opacity-100fade. - Give the peel a slight overshoot easing for a more physical paper feel.
Gotchas — read before shipping
- Prefer the transform to an animated
clip-path: polygon interpolation needs matching vertex counts and a mismatch snaps instead of tweening. - Set
[transform-origin:top_right]. With the default centre origin the card slides rather than peels. - Put something meaningful under the peel. An empty gradient behind the lifted corner reads as a bug.
- Keep the shadow blur modest — a large animated
drop-shadowis genuinely expensive on mobile. - Give the stack an explicit
z-indexper layer; source order alone will eventually disagree with the visual stack. - Under reduced motion, fade rather than peel — an off-origin rotate-and-scale is the exact motion profile to avoid.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 111+ | 16.4+ | 128+ | 111+ |
Transforms, transform-origin and asymmetric border-radius transitions are universal (Chrome 36+, Safari 9+, Firefox 16+). The floor is Tailwind v4's own generated sheet.