36 Tailwind Stacked Cards
04 / 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 Stacked Cards Expand Accordion on Click

A pile resting on its bottom edges that opens by animating grid rows, no JS. The 0fr → 1fr reveal is grid-rows-[0fr] with peer-checked:grid-rows-[1fr] — a real utility pair, not an arbitrary property. The open card lifts clear via has-checked:, which is exactly the :has() rule the CSS version needs, only typed on the panel it applies to.

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-04 w-full min-h-svh flex items-center justify-center px-5 py-12 font-stk04-sans bg-stk04-bg" aria-label="Stacked expansion accordion">
  <div class="w-[min(440px,100%)]">
    <div class="relative -mt-3 first:mt-0 rounded-2xl border border-stk04-line bg-stk04-card shadow-[0_14px_30px_-22px_rgba(0,0,0,0.8)] transition-[margin,box-shadow,border-color] duration-350 has-checked:mt-3.5 first:has-checked:mt-0 has-checked:z-2 has-checked:border-stk04-accent has-checked:shadow-[0_22px_46px_-26px_var(--color-stk04-accent)] motion-reduce:transition-none">
      <input class="peer sr-only" type="radio" name="stk-04" id="stk-04-1" checked>
      <label class="flex items-center gap-3 px-5 py-4.5 cursor-pointer rounded-2xl text-[15px] font-bold text-stk04-dim peer-checked:text-white peer-focus-visible:outline-3 peer-focus-visible:outline-stk04-accent peer-focus-visible:-outline-offset-3" for="stk-04-1">
        <span class="size-2 shrink-0 rounded-full bg-stk04-line transition-colors duration-300 peer-checked:bg-stk04-accent"></span>
        Dimensions &amp; weight
        <span class="ml-auto font-stk04-mono text-2xl leading-none text-stk04-muted transition-[transform,color] duration-300 peer-checked:rotate-90 peer-checked:text-stk04-accent motion-reduce:transition-none" aria-hidden="true">&rsaquo;</span>
      </label>
      <div class="grid grid-rows-[0fr] transition-[grid-template-rows] duration-400 ease-stk04 peer-checked:grid-rows-[1fr] motion-reduce:transition-none">
        <div class="overflow-hidden"><p class="px-5 pb-5 text-sm leading-relaxed text-stk04-muted">142 &times; 68 &times; 7.4 mm &middot; 168 g. Aerospace-grade aluminium frame with a matte bead-blast finish.</p></div>
      </div>
    </div>
    <div class="relative -mt-3 rounded-2xl border border-stk04-line bg-stk04-card shadow-[0_14px_30px_-22px_rgba(0,0,0,0.8)] transition-[margin,box-shadow,border-color] duration-350 has-checked:mt-3.5 has-checked:z-2 has-checked:border-stk04-accent has-checked:shadow-[0_22px_46px_-26px_var(--color-stk04-accent)] motion-reduce:transition-none">
      <input class="peer sr-only" type="radio" name="stk-04" id="stk-04-2">
      <label class="flex items-center gap-3 px-5 py-4.5 cursor-pointer rounded-2xl text-[15px] font-bold text-stk04-dim peer-checked:text-white peer-focus-visible:outline-3 peer-focus-visible:outline-stk04-accent peer-focus-visible:-outline-offset-3" for="stk-04-2">
        <span class="size-2 shrink-0 rounded-full bg-stk04-line transition-colors duration-300 peer-checked:bg-stk04-accent"></span>
        Display
        <span class="ml-auto font-stk04-mono text-2xl leading-none text-stk04-muted transition-[transform,color] duration-300 peer-checked:rotate-90 peer-checked:text-stk04-accent motion-reduce:transition-none" aria-hidden="true">&rsaquo;</span>
      </label>
      <div class="grid grid-rows-[0fr] transition-[grid-template-rows] duration-400 ease-stk04 peer-checked:grid-rows-[1fr] motion-reduce:transition-none">
        <div class="overflow-hidden"><p class="px-5 pb-5 text-sm leading-relaxed text-stk04-muted">6.3&Prime; LTPO OLED, 1&ndash;120 Hz adaptive, 2600 nits peak, Dolby Vision, hardened glass.</p></div>
      </div>
    </div>
    <div class="relative -mt-3 rounded-2xl border border-stk04-line bg-stk04-card shadow-[0_14px_30px_-22px_rgba(0,0,0,0.8)] transition-[margin,box-shadow,border-color] duration-350 has-checked:mt-3.5 has-checked:z-2 has-checked:border-stk04-accent has-checked:shadow-[0_22px_46px_-26px_var(--color-stk04-accent)] motion-reduce:transition-none">
      <input class="peer sr-only" type="radio" name="stk-04" id="stk-04-3">
      <label class="flex items-center gap-3 px-5 py-4.5 cursor-pointer rounded-2xl text-[15px] font-bold text-stk04-dim peer-checked:text-white peer-focus-visible:outline-3 peer-focus-visible:outline-stk04-accent peer-focus-visible:-outline-offset-3" for="stk-04-3">
        <span class="size-2 shrink-0 rounded-full bg-stk04-line transition-colors duration-300 peer-checked:bg-stk04-accent"></span>
        Battery &amp; charging
        <span class="ml-auto font-stk04-mono text-2xl leading-none text-stk04-muted transition-[transform,color] duration-300 peer-checked:rotate-90 peer-checked:text-stk04-accent motion-reduce:transition-none" aria-hidden="true">&rsaquo;</span>
      </label>
      <div class="grid grid-rows-[0fr] transition-[grid-template-rows] duration-400 ease-stk04 peer-checked:grid-rows-[1fr] motion-reduce:transition-none">
        <div class="overflow-hidden"><p class="px-5 pb-5 text-sm leading-relaxed text-stk04-muted">4,800 mAh &middot; 80 W wired to 50% in 12 min &middot; 30 W wireless &middot; USB-C 3.2.</p></div>
      </div>
    </div>
    <div class="relative -mt-3 rounded-2xl border border-stk04-line bg-stk04-card shadow-[0_14px_30px_-22px_rgba(0,0,0,0.8)] transition-[margin,box-shadow,border-color] duration-350 has-checked:mt-3.5 has-checked:z-2 has-checked:border-stk04-accent has-checked:shadow-[0_22px_46px_-26px_var(--color-stk04-accent)] motion-reduce:transition-none">
      <input class="peer sr-only" type="radio" name="stk-04" id="stk-04-4">
      <label class="flex items-center gap-3 px-5 py-4.5 cursor-pointer rounded-2xl text-[15px] font-bold text-stk04-dim peer-checked:text-white peer-focus-visible:outline-3 peer-focus-visible:outline-stk04-accent peer-focus-visible:-outline-offset-3" for="stk-04-4">
        <span class="size-2 shrink-0 rounded-full bg-stk04-line transition-colors duration-300 peer-checked:bg-stk04-accent"></span>
        In the box
        <span class="ml-auto font-stk04-mono text-2xl leading-none text-stk04-muted transition-[transform,color] duration-300 peer-checked:rotate-90 peer-checked:text-stk04-accent motion-reduce:transition-none" aria-hidden="true">&rsaquo;</span>
      </label>
      <div class="grid grid-rows-[0fr] transition-[grid-template-rows] duration-400 ease-stk04 peer-checked:grid-rows-[1fr] motion-reduce:transition-none">
        <div class="overflow-hidden"><p class="px-5 pb-5 text-sm leading-relaxed text-stk04-muted">Device, braided USB-C cable, SIM tool, quick-start guide. Adapter sold separately.</p></div>
      </div>
    </div>
  </div>
</section>
@import "tailwindcss";

@theme {
  --color-stk04-bg: #111319;
  --color-stk04-bg: oklch(0.20 0.012 265);
  --color-stk04-card: #1c1f28;
  --color-stk04-card: oklch(0.25 0.014 265);
  --color-stk04-line: #2a2e3a;
  --color-stk04-line: oklch(0.32 0.016 265);
  --color-stk04-dim: #eef0f6;
  --color-stk04-dim: oklch(0.94 0.006 265);
  --color-stk04-muted: #aab0c0;
  --color-stk04-muted: oklch(0.75 0.018 265);
  --color-stk04-accent: #6a7bf0;
  --color-stk04-accent: oklch(0.60 0.16 265);
  --font-stk04-sans: 'Archivo', system-ui, sans-serif;
  --font-stk04-mono: 'JetBrains Mono', ui-monospace, monospace;
  --ease-stk04: 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-stk04-bg: #111319;
  --color-stk04-bg: oklch(0.20 0.012 265);
  --color-stk04-card: #1c1f28;
  --color-stk04-card: oklch(0.25 0.014 265);
  --color-stk04-line: #2a2e3a;
  --color-stk04-line: oklch(0.32 0.016 265);
  --color-stk04-dim: #eef0f6;
  --color-stk04-dim: oklch(0.94 0.006 265);
  --color-stk04-muted: #aab0c0;
  --color-stk04-muted: oklch(0.75 0.018 265);
  --color-stk04-accent: #6a7bf0;
  --color-stk04-accent: oklch(0.60 0.16 265);
  --font-stk04-sans: 'Archivo', system-ui, sans-serif;
  --font-stk04-mono: 'JetBrains Mono', ui-monospace, monospace;
  --ease-stk04: 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,600;75..125,700&family=JetBrains+Mono: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.
  • This is the first demo in the collection whose stylesheet is nothing but @theme — every selector in the CSS version, including the :has() lift, has an exact variant.
  • grid-template-rows:0fr→1fr is a first-class utility pair here (grid-rows-[0fr] / peer-checked:grid-rows-[1fr]), not an arbitrary property.
  • The four .radio:checked ~ … rules become peer-checked: on the header, the dot and the chevron; the panel's :has() rule becomes has-checked: on the panel.
  • peer-* versus has-* is the whole port: the radio is a sibling of the header but a descendant of the panel, so each needs a different family of variant.
  • The scoped sr-only clip becomes Tailwind's own sr-only, which keeps the radios focusable so native arrow-key navigation survives.
  • The border-plus-shadow active state reads --color-stk04-accent in both places, including inside an arbitrary shadow — shadow-[0_22px_46px_-26px_var(--color-stk04-accent)].
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 Stacked Cards Expand Accordion on Click
Source: https://codefronts.com/components/tailwind-stacked-cards/tailwind-stacked-cards-expand-accordion-on-click/

A pile resting on its bottom edges that opens by animating grid rows, no JS. The 0fr &rarr; 1fr reveal is grid-rows-[0fr] with peer-checked:grid-rows-[1fr] &mdash; a real utility pair, not an arbitrary property. The open card lifts clear via has-checked:, which is exactly the :has() rule the CSS version needs, only typed on the panel it applies to.
## HTML
```html
<section class="stk-04 w-full min-h-svh flex items-center justify-center px-5 py-12 font-stk04-sans bg-stk04-bg" aria-label="Stacked expansion accordion">
  <div class="w-[min(440px,100%)]">
    <div class="relative -mt-3 first:mt-0 rounded-2xl border border-stk04-line bg-stk04-card shadow-[0_14px_30px_-22px_rgba(0,0,0,0.8)] transition-[margin,box-shadow,border-color] duration-350 has-checked:mt-3.5 first:has-checked:mt-0 has-checked:z-2 has-checked:border-stk04-accent has-checked:shadow-[0_22px_46px_-26px_var(--color-stk04-accent)] motion-reduce:transition-none">
      <input class="peer sr-only" type="radio" name="stk-04" id="stk-04-1" checked>
      <label class="flex items-center gap-3 px-5 py-4.5 cursor-pointer rounded-2xl text-[15px] font-bold text-stk04-dim peer-checked:text-white peer-focus-visible:outline-3 peer-focus-visible:outline-stk04-accent peer-focus-visible:-outline-offset-3" for="stk-04-1">
        <span class="size-2 shrink-0 rounded-full bg-stk04-line transition-colors duration-300 peer-checked:bg-stk04-accent"></span>
        Dimensions &amp; weight
        <span class="ml-auto font-stk04-mono text-2xl leading-none text-stk04-muted transition-[transform,color] duration-300 peer-checked:rotate-90 peer-checked:text-stk04-accent motion-reduce:transition-none" aria-hidden="true">&rsaquo;</span>
      </label>
      <div class="grid grid-rows-[0fr] transition-[grid-template-rows] duration-400 ease-stk04 peer-checked:grid-rows-[1fr] motion-reduce:transition-none">
        <div class="overflow-hidden"><p class="px-5 pb-5 text-sm leading-relaxed text-stk04-muted">142 &times; 68 &times; 7.4 mm &middot; 168 g. Aerospace-grade aluminium frame with a matte bead-blast finish.</p></div>
      </div>
    </div>
    <div class="relative -mt-3 rounded-2xl border border-stk04-line bg-stk04-card shadow-[0_14px_30px_-22px_rgba(0,0,0,0.8)] transition-[margin,box-shadow,border-color] duration-350 has-checked:mt-3.5 has-checked:z-2 has-checked:border-stk04-accent has-checked:shadow-[0_22px_46px_-26px_var(--color-stk04-accent)] motion-reduce:transition-none">
      <input class="peer sr-only" type="radio" name="stk-04" id="stk-04-2">
      <label class="flex items-center gap-3 px-5 py-4.5 cursor-pointer rounded-2xl text-[15px] font-bold text-stk04-dim peer-checked:text-white peer-focus-visible:outline-3 peer-focus-visible:outline-stk04-accent peer-focus-visible:-outline-offset-3" for="stk-04-2">
        <span class="size-2 shrink-0 rounded-full bg-stk04-line transition-colors duration-300 peer-checked:bg-stk04-accent"></span>
        Display
        <span class="ml-auto font-stk04-mono text-2xl leading-none text-stk04-muted transition-[transform,color] duration-300 peer-checked:rotate-90 peer-checked:text-stk04-accent motion-reduce:transition-none" aria-hidden="true">&rsaquo;</span>
      </label>
      <div class="grid grid-rows-[0fr] transition-[grid-template-rows] duration-400 ease-stk04 peer-checked:grid-rows-[1fr] motion-reduce:transition-none">
        <div class="overflow-hidden"><p class="px-5 pb-5 text-sm leading-relaxed text-stk04-muted">6.3&Prime; LTPO OLED, 1&ndash;120 Hz adaptive, 2600 nits peak, Dolby Vision, hardened glass.</p></div>
      </div>
    </div>
    <div class="relative -mt-3 rounded-2xl border border-stk04-line bg-stk04-card shadow-[0_14px_30px_-22px_rgba(0,0,0,0.8)] transition-[margin,box-shadow,border-color] duration-350 has-checked:mt-3.5 has-checked:z-2 has-checked:border-stk04-accent has-checked:shadow-[0_22px_46px_-26px_var(--color-stk04-accent)] motion-reduce:transition-none">
      <input class="peer sr-only" type="radio" name="stk-04" id="stk-04-3">
      <label class="flex items-center gap-3 px-5 py-4.5 cursor-pointer rounded-2xl text-[15px] font-bold text-stk04-dim peer-checked:text-white peer-focus-visible:outline-3 peer-focus-visible:outline-stk04-accent peer-focus-visible:-outline-offset-3" for="stk-04-3">
        <span class="size-2 shrink-0 rounded-full bg-stk04-line transition-colors duration-300 peer-checked:bg-stk04-accent"></span>
        Battery &amp; charging
        <span class="ml-auto font-stk04-mono text-2xl leading-none text-stk04-muted transition-[transform,color] duration-300 peer-checked:rotate-90 peer-checked:text-stk04-accent motion-reduce:transition-none" aria-hidden="true">&rsaquo;</span>
      </label>
      <div class="grid grid-rows-[0fr] transition-[grid-template-rows] duration-400 ease-stk04 peer-checked:grid-rows-[1fr] motion-reduce:transition-none">
        <div class="overflow-hidden"><p class="px-5 pb-5 text-sm leading-relaxed text-stk04-muted">4,800 mAh &middot; 80 W wired to 50% in 12 min &middot; 30 W wireless &middot; USB-C 3.2.</p></div>
      </div>
    </div>
    <div class="relative -mt-3 rounded-2xl border border-stk04-line bg-stk04-card shadow-[0_14px_30px_-22px_rgba(0,0,0,0.8)] transition-[margin,box-shadow,border-color] duration-350 has-checked:mt-3.5 has-checked:z-2 has-checked:border-stk04-accent has-checked:shadow-[0_22px_46px_-26px_var(--color-stk04-accent)] motion-reduce:transition-none">
      <input class="peer sr-only" type="radio" name="stk-04" id="stk-04-4">
      <label class="flex items-center gap-3 px-5 py-4.5 cursor-pointer rounded-2xl text-[15px] font-bold text-stk04-dim peer-checked:text-white peer-focus-visible:outline-3 peer-focus-visible:outline-stk04-accent peer-focus-visible:-outline-offset-3" for="stk-04-4">
        <span class="size-2 shrink-0 rounded-full bg-stk04-line transition-colors duration-300 peer-checked:bg-stk04-accent"></span>
        In the box
        <span class="ml-auto font-stk04-mono text-2xl leading-none text-stk04-muted transition-[transform,color] duration-300 peer-checked:rotate-90 peer-checked:text-stk04-accent motion-reduce:transition-none" aria-hidden="true">&rsaquo;</span>
      </label>
      <div class="grid grid-rows-[0fr] transition-[grid-template-rows] duration-400 ease-stk04 peer-checked:grid-rows-[1fr] motion-reduce:transition-none">
        <div class="overflow-hidden"><p class="px-5 pb-5 text-sm leading-relaxed text-stk04-muted">Device, braided USB-C cable, SIM tool, quick-start guide. Adapter sold separately.</p></div>
      </div>
    </div>
  </div>
</section>
```
## CSS
```css
@import "tailwindcss";

@theme {
  --color-stk04-bg: #111319;
  --color-stk04-bg: oklch(0.20 0.012 265);
  --color-stk04-card: #1c1f28;
  --color-stk04-card: oklch(0.25 0.014 265);
  --color-stk04-line: #2a2e3a;
  --color-stk04-line: oklch(0.32 0.016 265);
  --color-stk04-dim: #eef0f6;
  --color-stk04-dim: oklch(0.94 0.006 265);
  --color-stk04-muted: #aab0c0;
  --color-stk04-muted: oklch(0.75 0.018 265);
  --color-stk04-accent: #6a7bf0;
  --color-stk04-accent: oklch(0.60 0.16 265);
  --font-stk04-sans: 'Archivo', system-ui, sans-serif;
  --font-stk04-mono: 'JetBrains Mono', ui-monospace, monospace;
  --ease-stk04: cubic-bezier(0.3, 0.9, 0.3, 1);
}
```

How this works

The reveal is a grid utility, not a hack. height:auto cannot be transitioned, so the body sits in a one-row grid that animates between fractions. Tailwind has a real scale for this:

<div class="grid grid-rows-[0fr] peer-checked:grid-rows-[1fr]
            transition-[grid-template-rows] duration-400">
  <div class="overflow-hidden">…</div>
</div>

The inner overflow-hidden is mandatory. Without it the collapsed row is zero-height but its content still paints straight through.

peer and has-checked divide the work. The radio is a previous sibling of the header, so peer-checked: reaches the header, the status dot and the chevron. It is a descendant of the panel, so the panel cannot use peer-* and uses has-checked:mt-3.5 has-checked:border-stk04-accent instead. Getting this pairing wrong is the most common port bug in radio-driven CSS: peer-* only ever looks at earlier siblings.

Hidden but focusable. The radios use sr-only, which clips them without removing them from the tab order, so native arrow-key navigation between radios still works. The visible ring is drawn on the label with peer-focus-visible:outline-3, since the element that actually receives focus has no box to paint.

The stack look is document flow, not absolute positioning. Panels overlap with -mt-3 and simply reflow when one grows — which is why this stack, unlike the absolute ones in this collection, needs no fixed height and never clips at small widths.

Make it yours

  • Allow several panels open at once by switching the inputs to type=&quot;checkbox&quot; and dropping the shared name; every variant in the markup keeps working.
  • Change the resting overlap with the -mt-3 value, and the open card's clearance with has-checked:mt-3.5.
  • Retime the reveal via duration-400 on the grid wrapper.
  • Recolour the active state through --color-stk04-accent in @theme — the border, the dot and the chevron all read it.
  • Start collapsed by removing checked from the first input; the layout does not depend on one being open.

Gotchas — read before shipping

  • Animate grid-template-rows, never height:auto. And name it: transition-all does not cover it reliably across engines.
  • overflow-hidden on the inner wrapper is required — the grid row collapses but the content does not clip itself.
  • peer-* only matches previous siblings. The panel itself needs has-checked:; reaching for peer-checked: there silently does nothing.
  • Use sr-only, not hidden or opacity-0 pointer-events-none, on the radios. display:none removes them from the tab order and kills arrow-key navigation.
  • first:mt-0 has to be repeated on the has-checked: path (first:has-checked:mt-0), or the first panel jumps when it opens.
  • Give the label a real hit target. py-4.5 keeps every header above the 44px minimum on touch.

Browser support

ChromeSafariFirefoxEdge
111+16.4+128+111+

Animating grid-template-rows to 0fr/1fr needs Chrome 107+, Safari 16+, Firefox 66+; older engines snap open without the tween. has-checked: compiles to :has(), which is inside Tailwind v4's own floor.

Techniques used in this demo

Theme tokensset in @theme, used by a utility

Arbitraryneeds bracket syntax

Search CodeFronts

Loading…