36 Tailwind Stacked Cards
35 / 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 Timeline Stacked Milestone Cards

A gradient-spine timeline whose cards slide right and whose nodes bloom on hover. The port's contribution is semantic rather than visual: the div soup becomes a real <ol> with <time datetime> elements, and both the spine and the milestone nodes become before: utilities on the elements they belong to instead of two floating pseudo-element rules.

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-35 grid w-full min-h-svh place-items-center px-5 py-15 font-stk35-sans bg-linear-[180deg,var(--color-stk35-p1),var(--color-stk35-p2)]" aria-label="Company timeline">
  <ol class="relative m-0 w-[min(340px,92vw)] list-none pl-10 before:absolute before:inset-y-2.5 before:left-3.5 before:w-[3px] before:rounded before:bg-linear-[180deg,var(--color-stk35-spine1),var(--color-stk35-spine2)]">
    <li class="group relative mb-3.5 before:absolute before:-left-[33px] before:top-4.5 before:size-4 before:rounded-full before:border-[3px] before:border-stk35-spine1 before:bg-white before:transition-[transform,background-color] before:duration-350 hover:before:scale-130 hover:before:bg-stk35-accent motion-reduce:before:transition-none">
      <div class="cursor-pointer rounded-[14px] bg-white px-5 py-4 shadow-[0_8px_20px_rgba(120,60,80,0.12)] transition-[transform,box-shadow] duration-350 ease-stk35 group-hover:translate-x-3 group-hover:shadow-[0_14px_30px_rgba(120,60,80,0.2)] motion-reduce:transition-none motion-reduce:translate-none!">
        <time class="font-stk35-display text-[0.8rem] tracking-[0.08em] text-stk35-accent" datetime="2021-03">2021</time>
        <h3 class="m-0 mt-0.5 mb-1 font-stk35-display text-[1.1rem] text-stk35-ink">The Beginning</h3>
        <p class="m-0 text-[0.85rem] text-stk35-body">First prototype shipped to ten beta users.</p>
      </div>
    </li>
    <li class="group relative mb-3.5 before:absolute before:-left-[33px] before:top-4.5 before:size-4 before:rounded-full before:border-[3px] before:border-stk35-spine1 before:bg-white before:transition-[transform,background-color] before:duration-350 hover:before:scale-130 hover:before:bg-stk35-accent motion-reduce:before:transition-none">
      <div class="cursor-pointer rounded-[14px] bg-white px-5 py-4 shadow-[0_8px_20px_rgba(120,60,80,0.12)] transition-[transform,box-shadow] duration-350 ease-stk35 group-hover:translate-x-3 group-hover:shadow-[0_14px_30px_rgba(120,60,80,0.2)] motion-reduce:transition-none motion-reduce:translate-none!">
        <time class="font-stk35-display text-[0.8rem] tracking-[0.08em] text-stk35-accent" datetime="2023-06">2023</time>
        <h3 class="m-0 mt-0.5 mb-1 font-stk35-display text-[1.1rem] text-stk35-ink">Going Public</h3>
        <p class="m-0 text-[0.85rem] text-stk35-body">Launched the open platform to everyone.</p>
      </div>
    </li>
    <li class="group relative mb-3.5 before:absolute before:-left-[33px] before:top-4.5 before:size-4 before:rounded-full before:border-[3px] before:border-stk35-spine1 before:bg-white before:transition-[transform,background-color] before:duration-350 hover:before:scale-130 hover:before:bg-stk35-accent motion-reduce:before:transition-none">
      <div class="cursor-pointer rounded-[14px] bg-white px-5 py-4 shadow-[0_8px_20px_rgba(120,60,80,0.12)] transition-[transform,box-shadow] duration-350 ease-stk35 group-hover:translate-x-3 group-hover:shadow-[0_14px_30px_rgba(120,60,80,0.2)] motion-reduce:transition-none motion-reduce:translate-none!">
        <time class="font-stk35-display text-[0.8rem] tracking-[0.08em] text-stk35-accent" datetime="2025-01">2025</time>
        <h3 class="m-0 mt-0.5 mb-1 font-stk35-display text-[1.1rem] text-stk35-ink">Scale</h3>
        <p class="m-0 text-[0.85rem] text-stk35-body">Crossed one million active accounts.</p>
      </div>
    </li>
    <li class="group relative before:absolute before:-left-[33px] before:top-4.5 before:size-4 before:rounded-full before:border-[3px] before:border-stk35-spine2 before:bg-white before:transition-[transform,background-color] before:duration-350 hover:before:scale-130 hover:before:bg-stk35-accent motion-reduce:before:transition-none">
      <div class="cursor-pointer rounded-[14px] bg-white px-5 py-4 shadow-[0_8px_20px_rgba(120,60,80,0.12)] transition-[transform,box-shadow] duration-350 ease-stk35 group-hover:translate-x-3 group-hover:shadow-[0_14px_30px_rgba(120,60,80,0.2)] motion-reduce:transition-none motion-reduce:translate-none!">
        <time class="font-stk35-display text-[0.8rem] tracking-[0.08em] text-stk35-accent" datetime="2026-09">2026</time>
        <h3 class="m-0 mt-0.5 mb-1 font-stk35-display text-[1.1rem] text-stk35-ink">What&rsquo;s Next</h3>
        <p class="m-0 text-[0.85rem] text-stk35-body">Reimagining the experience from scratch.</p>
      </div>
    </li>
  </ol>
</section>
@import "tailwindcss";

@theme {
  --color-stk35-p1: #fffaf0;
  --color-stk35-p1: oklch(0.98 0.014 90);
  --color-stk35-p2: #f0e8dc;
  --color-stk35-p2: oklch(0.93 0.016 80);
  --color-stk35-spine1: #ff8a5c;
  --color-stk35-spine1: oklch(0.74 0.145 45);
  --color-stk35-spine2: #a83279;
  --color-stk35-spine2: oklch(0.47 0.170 350);
  --color-stk35-accent: #a83279;
  --color-stk35-accent: oklch(0.47 0.170 350);
  --color-stk35-ink: #2a2024;
  --color-stk35-ink: oklch(0.26 0.014 20);
  --color-stk35-body: #6a5a60;
  --color-stk35-body: oklch(0.50 0.018 10);
  --font-stk35-sans: 'Schibsted Grotesk', system-ui, sans-serif;
  --font-stk35-display: 'Bricolage Grotesque', system-ui, sans-serif;
  --ease-stk35: 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-stk35-p1: #fffaf0;
  --color-stk35-p1: oklch(0.98 0.014 90);
  --color-stk35-p2: #f0e8dc;
  --color-stk35-p2: oklch(0.93 0.016 80);
  --color-stk35-spine1: #ff8a5c;
  --color-stk35-spine1: oklch(0.74 0.145 45);
  --color-stk35-spine2: #a83279;
  --color-stk35-spine2: oklch(0.47 0.170 350);
  --color-stk35-accent: #a83279;
  --color-stk35-accent: oklch(0.47 0.170 350);
  --color-stk35-ink: #2a2024;
  --color-stk35-ink: oklch(0.26 0.014 20);
  --color-stk35-body: #6a5a60;
  --color-stk35-body: oklch(0.50 0.018 10);
  --font-stk35-sans: 'Schibsted Grotesk', system-ui, sans-serif;
  --font-stk35-display: 'Bricolage Grotesque', system-ui, sans-serif;
  --ease-stk35: 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=Bricolage+Grotesque:wght@700&family=Schibsted+Grotesk: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.
  • The substantive change is semantic: an <ol> of <li> milestones with <time datetime>, so sequence and dates are machine-readable rather than implied by styling.
  • Both pseudo-elements move onto their owners — the spine as a before: chain on the list, each node as a before: chain on its milestone.
  • The node's hover response is group-hover:before:scale-130: a variant reaching a pseudo-element, which the CSS version needs a second rule for.
  • The looping pulse becomes a hover bloom, which is why this demo ships no @keyframes and needs no motion off-switch for the node.
  • list-none keeps the list semantics while dropping the markers — the right way to style a list, rather than changing the element.
  • Status and dates are carried in words and attributes rather than colour, so the timeline survives being read aloud.
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 Timeline Stacked Milestone Cards
Source: https://codefronts.com/components/tailwind-stacked-cards/tailwind-timeline-stacked-milestone-cards/

A gradient-spine timeline whose cards slide right and whose nodes bloom on hover. The port's contribution is semantic rather than visual: the div soup becomes a real <ol> with <time datetime> elements, and both the spine and the milestone nodes become before: utilities on the elements they belong to instead of two floating pseudo-element rules.
## HTML
```html
<section class="stk-35 grid w-full min-h-svh place-items-center px-5 py-15 font-stk35-sans bg-linear-[180deg,var(--color-stk35-p1),var(--color-stk35-p2)]" aria-label="Company timeline">
  <ol class="relative m-0 w-[min(340px,92vw)] list-none pl-10 before:absolute before:inset-y-2.5 before:left-3.5 before:w-[3px] before:rounded before:bg-linear-[180deg,var(--color-stk35-spine1),var(--color-stk35-spine2)]">
    <li class="group relative mb-3.5 before:absolute before:-left-[33px] before:top-4.5 before:size-4 before:rounded-full before:border-[3px] before:border-stk35-spine1 before:bg-white before:transition-[transform,background-color] before:duration-350 hover:before:scale-130 hover:before:bg-stk35-accent motion-reduce:before:transition-none">
      <div class="cursor-pointer rounded-[14px] bg-white px-5 py-4 shadow-[0_8px_20px_rgba(120,60,80,0.12)] transition-[transform,box-shadow] duration-350 ease-stk35 group-hover:translate-x-3 group-hover:shadow-[0_14px_30px_rgba(120,60,80,0.2)] motion-reduce:transition-none motion-reduce:translate-none!">
        <time class="font-stk35-display text-[0.8rem] tracking-[0.08em] text-stk35-accent" datetime="2021-03">2021</time>
        <h3 class="m-0 mt-0.5 mb-1 font-stk35-display text-[1.1rem] text-stk35-ink">The Beginning</h3>
        <p class="m-0 text-[0.85rem] text-stk35-body">First prototype shipped to ten beta users.</p>
      </div>
    </li>
    <li class="group relative mb-3.5 before:absolute before:-left-[33px] before:top-4.5 before:size-4 before:rounded-full before:border-[3px] before:border-stk35-spine1 before:bg-white before:transition-[transform,background-color] before:duration-350 hover:before:scale-130 hover:before:bg-stk35-accent motion-reduce:before:transition-none">
      <div class="cursor-pointer rounded-[14px] bg-white px-5 py-4 shadow-[0_8px_20px_rgba(120,60,80,0.12)] transition-[transform,box-shadow] duration-350 ease-stk35 group-hover:translate-x-3 group-hover:shadow-[0_14px_30px_rgba(120,60,80,0.2)] motion-reduce:transition-none motion-reduce:translate-none!">
        <time class="font-stk35-display text-[0.8rem] tracking-[0.08em] text-stk35-accent" datetime="2023-06">2023</time>
        <h3 class="m-0 mt-0.5 mb-1 font-stk35-display text-[1.1rem] text-stk35-ink">Going Public</h3>
        <p class="m-0 text-[0.85rem] text-stk35-body">Launched the open platform to everyone.</p>
      </div>
    </li>
    <li class="group relative mb-3.5 before:absolute before:-left-[33px] before:top-4.5 before:size-4 before:rounded-full before:border-[3px] before:border-stk35-spine1 before:bg-white before:transition-[transform,background-color] before:duration-350 hover:before:scale-130 hover:before:bg-stk35-accent motion-reduce:before:transition-none">
      <div class="cursor-pointer rounded-[14px] bg-white px-5 py-4 shadow-[0_8px_20px_rgba(120,60,80,0.12)] transition-[transform,box-shadow] duration-350 ease-stk35 group-hover:translate-x-3 group-hover:shadow-[0_14px_30px_rgba(120,60,80,0.2)] motion-reduce:transition-none motion-reduce:translate-none!">
        <time class="font-stk35-display text-[0.8rem] tracking-[0.08em] text-stk35-accent" datetime="2025-01">2025</time>
        <h3 class="m-0 mt-0.5 mb-1 font-stk35-display text-[1.1rem] text-stk35-ink">Scale</h3>
        <p class="m-0 text-[0.85rem] text-stk35-body">Crossed one million active accounts.</p>
      </div>
    </li>
    <li class="group relative before:absolute before:-left-[33px] before:top-4.5 before:size-4 before:rounded-full before:border-[3px] before:border-stk35-spine2 before:bg-white before:transition-[transform,background-color] before:duration-350 hover:before:scale-130 hover:before:bg-stk35-accent motion-reduce:before:transition-none">
      <div class="cursor-pointer rounded-[14px] bg-white px-5 py-4 shadow-[0_8px_20px_rgba(120,60,80,0.12)] transition-[transform,box-shadow] duration-350 ease-stk35 group-hover:translate-x-3 group-hover:shadow-[0_14px_30px_rgba(120,60,80,0.2)] motion-reduce:transition-none motion-reduce:translate-none!">
        <time class="font-stk35-display text-[0.8rem] tracking-[0.08em] text-stk35-accent" datetime="2026-09">2026</time>
        <h3 class="m-0 mt-0.5 mb-1 font-stk35-display text-[1.1rem] text-stk35-ink">What&rsquo;s Next</h3>
        <p class="m-0 text-[0.85rem] text-stk35-body">Reimagining the experience from scratch.</p>
      </div>
    </li>
  </ol>
</section>
```
## CSS
```css
@import "tailwindcss";

@theme {
  --color-stk35-p1: #fffaf0;
  --color-stk35-p1: oklch(0.98 0.014 90);
  --color-stk35-p2: #f0e8dc;
  --color-stk35-p2: oklch(0.93 0.016 80);
  --color-stk35-spine1: #ff8a5c;
  --color-stk35-spine1: oklch(0.74 0.145 45);
  --color-stk35-spine2: #a83279;
  --color-stk35-spine2: oklch(0.47 0.170 350);
  --color-stk35-accent: #a83279;
  --color-stk35-accent: oklch(0.47 0.170 350);
  --color-stk35-ink: #2a2024;
  --color-stk35-ink: oklch(0.26 0.014 20);
  --color-stk35-body: #6a5a60;
  --color-stk35-body: oklch(0.50 0.018 10);
  --font-stk35-sans: 'Schibsted Grotesk', system-ui, sans-serif;
  --font-stk35-display: 'Bricolage Grotesque', system-ui, sans-serif;
  --ease-stk35: cubic-bezier(0.3, 0.9, 0.3, 1);
}
```

How this works

The markup change is the real port. A timeline is an ordered list, and saying so gets you sequence for free in the accessibility tree, plus dates search engines and assistants can parse:

<ol class="list-none relative pl-10 before:absolute …">
  <li class="group relative mb-3.5 before:absolute …">
    <time datetime="2021-03-01">2021</time>

The visual result is identical; what changes is that the structure is now true.

Both pseudo-elements move into the markup. The spine belongs to the list and the node belongs to the milestone, and as before: chains each one sits on its owner. The node's hover response — group-hover:before:scale-130 group-hover:before:bg-stk35-accent — is then two utilities next to the element it decorates rather than a second rule keyed on a class name.

A pulse is a loop; a bloom is a response. The CSS version reaches for a pulsing @keyframes. A scale-and-fill on hover conveys the same focus without any autoplaying animation to suppress under reduced motion — which is why this demo needs no keyframes at all.

Short entries, by design. Timelines are scanned, not read. Keeping each milestone under about forty words is a content constraint that the layout should enforce rather than fight.

Make it yours

  • Rebrand the spine through the two gradient tokens; the node border and hover fill read the same accent.
  • Change the node shape by swapping before:rounded-full for a square or a rotated diamond.
  • Set the slide distance with group-hover:translate-x-3.
  • Add status pills (Shipped / In progress / Planned) inside each card, with the status in words as well as colour.
  • Collapse to full-width cards below sm: by reducing the list's left padding and the node offset.

Gotchas — read before shipping

  • Use <ol> and <time datetime>. A timeline built from divs loses its sequence in the accessibility tree and its dates to any parser.
  • Keep list-none rather than changing the element — you want the semantics without the markers.
  • The node is positioned relative to its <li>, so the list's left padding and the node's negative offset have to stay in step.
  • Prefer a hover bloom to a looping pulse; a loop needs a reduced-motion off-switch and adds nothing here.
  • Never encode status in colour alone — put the word in the card.
  • Keep entries under about forty words; a timeline that has to be read line by line is a list in disguise.

Browser support

ChromeSafariFirefoxEdge
111+16.4+128+111+

Flex, gradients and pseudo-elements are universal (Chrome 45+, Safari 9+, Firefox 16+). 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…