30 Tailwind CSS Sidebar Layouts
15 / 30

All 30 in 30 Tailwind CSS Sidebar Layouts

  1. 01Tailwind SaaS Dashboard Sidebar with Native Dark Mode Switch
  2. 02Tailwind Collapsible Admin Sidebar with Icon Tooltips
  3. 03Tailwind Documentation Sidebar with Multi-Level :target Tree
  4. 04Tailwind Responsive Sidebar to Bottom Navigation Switch Layout
  5. 05Tailwind Analytics Sidebar with CSS Subgrid Column Alignment
  6. 06Tailwind Animated Collapsible Sidebar with Icon-Only Mode
  7. 07Tailwind Sticky Sidebar Layout with Scroll-Driven Progress Bar
  8. 08Tailwind Pure CSS Collapsible Sidebar Drawer without JavaScript
  9. 09Tailwind Fixed Sidebar Layout with Independently Scrolling Content
  10. 10Tailwind Off-Canvas Navigation Drawer with the Popover API
  11. 11Tailwind Right-Aligned Sidebar Layout for Inspector Panels
  12. 12Tailwind Two-Pane Webmail Layout with List and Reading Pane
  13. 13Tailwind Dual Sidebar App Shell with Left Nav and Context Panel
  14. 14Tailwind Mini Icon Rail Sidebar with Anchor-Positioned Active Pill
  15. 15Tailwind E-Commerce Filter Sidebar with Native Details Accordion
  16. 16Tailwind Floating Glassmorphism Sidebar with Gradient Hairline
  17. 17Tailwind Sidebar Menu with Pinned User Profile Footer
  18. 18Tailwind Push-Content Sidebar Drawer with GPU Transitions
  19. 19Tailwind Off-Canvas Cart Overlay with Blurred Backdrop Scrim
  20. 20Tailwind Sidebar with Persistent Collapsed State in localStorage
  21. 21Tailwind Sidebar with Sticky Search Bar Inside the Rail
  22. 22Tailwind Section-Grouped Sidebar Navigation with Header Labels
  23. 23Tailwind Sliding Active Indicator Sidebar with CSS :target
  24. 24Tailwind Multi-Level Nested Tree Sidebar with Details Branches
  25. 25Tailwind Tabbed Sidebar with Radio-Driven Panel Switching
  26. 26Tailwind Onboarding Wizard Sidebar with Step Progress Tracking
  27. 27Tailwind Resizable Sidebar Layout Using the CSS Resize Property
  28. 28Tailwind Three-Pane Workspace Shell with Icon Rail and List
  29. 29Tailwind Adaptive Sidebar Layout Using CSS Container Queries
  30. 30Tailwind Frosted Glass Floating Sidebar with Animated Aurora
Pure TailwindMIT licensed

Tailwind E-Commerce Filter Sidebar with Native Details Accordion

A storefront filter rail built entirely on native <details>/<summary> — keyboard-operable, screen-reader-announced and crawlable with zero script. v4's open: variant styles the expanded state, and accent-color brands every checkbox in one utility.

Live Demo
Plain CSSTailwind v4
Try it

Mosaic by Cruip: a complete Tailwind admin dashboard template in HTML, React, Next.js and Vue · $69

Cruip · Mosaic by Cruip · Affiliate link

View Mosaic dashboard

The code

<section class="tsl-15 w-full h-svh min-h-svh overflow-y-auto grid grid-cols-[250px_1fr] gap-7 p-7 font-tsl15-sans bg-tsl15-bg text-tsl15-ink">
  <aside aria-label="Product filters" class="sticky top-0 self-start max-h-[calc(100svh-3.5rem)] overflow-y-auto flex flex-col gap-1">
    <h2 class="flex justify-between items-baseline px-0.5 pt-1 pb-3.5 text-[15px] font-bold">Filters <button type="button" class="min-h-11 px-1 border-0 bg-transparent text-tsl15-accent text-[12.5px] font-medium underline underline-offset-[3px] cursor-pointer rounded focus-visible:outline-2 focus-visible:outline-tsl15-accent focus-visible:outline-offset-2">Clear all</button></h2>
    <details name="tsl15-filters" open class="group border-t border-tsl15-line">
      <summary class="flex items-center gap-2 min-h-11 px-0.5 text-[13.5px] font-semibold cursor-pointer list-none rounded-md [&amp;::-webkit-details-marker]:hidden focus-visible:outline-2 focus-visible:outline-tsl15-accent focus-visible:outline-offset-2">Category <span class="ml-auto text-[11.5px] font-medium text-tsl15-mut">128</span><svg viewBox="0 0 24 24" aria-hidden="true" class="w-4 h-4 fill-none stroke-tsl15-mut stroke-2 [stroke-linecap:round] [stroke-linejoin:round] transition-[rotate] duration-[250ms] group-open:rotate-180 motion-reduce:transition-none"><path d="m6 9 6 6 6-6"/></svg></summary>
      <div class="flex flex-col gap-2.5 px-0.5 pt-0.5 pb-4">
        <label class="flex items-center gap-2.5 min-h-11 text-[13.5px] cursor-pointer"><input type="checkbox" checked class="w-4 h-4 accent-tsl15-accent focus-visible:outline-2 focus-visible:outline-tsl15-accent focus-visible:outline-offset-2">Sneakers <span class="ml-auto text-[11.5px] text-tsl15-mut">64</span></label>
        <label class="flex items-center gap-2.5 min-h-11 text-[13.5px] cursor-pointer"><input type="checkbox" class="w-4 h-4 accent-tsl15-accent focus-visible:outline-2 focus-visible:outline-tsl15-accent focus-visible:outline-offset-2">Running <span class="ml-auto text-[11.5px] text-tsl15-mut">38</span></label>
        <label class="flex items-center gap-2.5 min-h-11 text-[13.5px] cursor-pointer"><input type="checkbox" class="w-4 h-4 accent-tsl15-accent focus-visible:outline-2 focus-visible:outline-tsl15-accent focus-visible:outline-offset-2">Trail <span class="ml-auto text-[11.5px] text-tsl15-mut">26</span></label>
      </div>
    </details>
    <details name="tsl15-filters" class="group border-t border-tsl15-line">
      <summary class="flex items-center gap-2 min-h-11 px-0.5 text-[13.5px] font-semibold cursor-pointer list-none rounded-md [&amp;::-webkit-details-marker]:hidden focus-visible:outline-2 focus-visible:outline-tsl15-accent focus-visible:outline-offset-2">Price <span class="ml-auto text-[11.5px] font-medium text-tsl15-mut">$40&ndash;220</span><svg viewBox="0 0 24 24" aria-hidden="true" class="w-4 h-4 fill-none stroke-tsl15-mut stroke-2 [stroke-linecap:round] [stroke-linejoin:round] transition-[rotate] duration-[250ms] group-open:rotate-180 motion-reduce:transition-none"><path d="m6 9 6 6 6-6"/></svg></summary>
      <div class="flex flex-col gap-2.5 px-0.5 pt-0.5 pb-4">
        <input type="range" min="40" max="220" value="120" aria-label="Maximum price" class="w-full accent-tsl15-accent focus-visible:outline-2 focus-visible:outline-tsl15-accent focus-visible:outline-offset-2">
        <label class="flex items-center gap-2.5 min-h-11 text-[13.5px] cursor-pointer"><input type="checkbox" class="w-4 h-4 accent-tsl15-accent focus-visible:outline-2 focus-visible:outline-tsl15-accent focus-visible:outline-offset-2">Under $80 <span class="ml-auto text-[11.5px] text-tsl15-mut">31</span></label>
        <label class="flex items-center gap-2.5 min-h-11 text-[13.5px] cursor-pointer"><input type="checkbox" class="w-4 h-4 accent-tsl15-accent focus-visible:outline-2 focus-visible:outline-tsl15-accent focus-visible:outline-offset-2">$80&ndash;$150 <span class="ml-auto text-[11.5px] text-tsl15-mut">57</span></label>
      </div>
    </details>
    <details name="tsl15-filters" class="group border-t border-tsl15-line">
      <summary class="flex items-center gap-2 min-h-11 px-0.5 text-[13.5px] font-semibold cursor-pointer list-none rounded-md [&amp;::-webkit-details-marker]:hidden focus-visible:outline-2 focus-visible:outline-tsl15-accent focus-visible:outline-offset-2">Brand <span class="ml-auto text-[11.5px] font-medium text-tsl15-mut">12</span><svg viewBox="0 0 24 24" aria-hidden="true" class="w-4 h-4 fill-none stroke-tsl15-mut stroke-2 [stroke-linecap:round] [stroke-linejoin:round] transition-[rotate] duration-[250ms] group-open:rotate-180 motion-reduce:transition-none"><path d="m6 9 6 6 6-6"/></svg></summary>
      <div class="flex flex-col gap-2.5 px-0.5 pt-0.5 pb-4">
        <label class="flex items-center gap-2.5 min-h-11 text-[13.5px] cursor-pointer"><input type="checkbox" class="w-4 h-4 accent-tsl15-accent focus-visible:outline-2 focus-visible:outline-tsl15-accent focus-visible:outline-offset-2">Veloce <span class="ml-auto text-[11.5px] text-tsl15-mut">44</span></label>
        <label class="flex items-center gap-2.5 min-h-11 text-[13.5px] cursor-pointer"><input type="checkbox" class="w-4 h-4 accent-tsl15-accent focus-visible:outline-2 focus-visible:outline-tsl15-accent focus-visible:outline-offset-2">Northpeak <span class="ml-auto text-[11.5px] text-tsl15-mut">29</span></label>
        <label class="flex items-center gap-2.5 min-h-11 text-[13.5px] cursor-pointer"><input type="checkbox" class="w-4 h-4 accent-tsl15-accent focus-visible:outline-2 focus-visible:outline-tsl15-accent focus-visible:outline-offset-2">Atlasform <span class="ml-auto text-[11.5px] text-tsl15-mut">18</span></label>
      </div>
    </details>
  </aside>
  <main aria-label="Products" class="grid grid-cols-[repeat(auto-fill,minmax(160px,1fr))] gap-[18px] content-start">
    <article><div class="aspect-square rounded-xl bg-[linear-gradient(135deg,oklch(0.93_0.01_265),oklch(0.88_0.015_265))]"></div><h3 class="mt-2.5 text-[13.5px] font-semibold leading-snug">Veloce Cloudrunner</h3><p class="mt-1 text-[13px] font-medium text-tsl15-mut">$128</p></article>
    <article><div class="aspect-square rounded-xl bg-[linear-gradient(135deg,oklch(0.93_0.01_265),oklch(0.88_0.015_265))]"></div><h3 class="mt-2.5 text-[13.5px] font-semibold leading-snug">Northpeak Trail 2</h3><p class="mt-1 text-[13px] font-medium text-tsl15-mut">$156</p></article>
    <article><div class="aspect-square rounded-xl bg-[linear-gradient(135deg,oklch(0.93_0.01_265),oklch(0.88_0.015_265))]"></div><h3 class="mt-2.5 text-[13.5px] font-semibold leading-snug">Atlasform Daily</h3><p class="mt-1 text-[13px] font-medium text-tsl15-mut">$92</p></article>
    <article><div class="aspect-square rounded-xl bg-[linear-gradient(135deg,oklch(0.93_0.01_265),oklch(0.88_0.015_265))]"></div><h3 class="mt-2.5 text-[13.5px] font-semibold leading-snug">Veloce Street LX</h3><p class="mt-1 text-[13px] font-medium text-tsl15-mut">$110</p></article>
  </main>
</section>
@import "tailwindcss";

@theme {
  --color-tsl15-bg: #fbfbf9;
  --color-tsl15-bg: oklch(0.98 0.003 100);
  --color-tsl15-ink: #393d45;
  --color-tsl15-ink: oklch(0.26 0.015 265);
  --color-tsl15-mut: #7c8089;
  --color-tsl15-mut: oklch(0.55 0.012 265);
  --color-tsl15-line: #e6e7eb;
  --color-tsl15-line: oklch(0.91 0.006 265);
  --color-tsl15-accent: #c23d2e;
  --color-tsl15-accent: oklch(0.55 0.19 25);
  --font-tsl15-sans: 'Plus Jakarta Sans', system-ui, sans-serif;
}

.tsl-15 {
  width: 100%;
  height: 100svh;
  min-height: 100svh;
  color-scheme: light;
  interpolate-size: allow-keywords;
}
/* ::details-content has no variant, and interpolate-size is an inherited
   property set once — both are stylesheet concerns, not class-list ones. */

.tsl-15 details::details-content {
  height: 0;
  overflow: clip;
  transition: height .3s ease, content-visibility .3s allow-discrete;
}

.tsl-15 details[open]::details-content {
  height: auto;
}

@media (prefers-reduced-motion: reduce) {
  .tsl-15 details::details-content {
    transition: none;
  }
}

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-tsl15-bg: #fbfbf9;
  --color-tsl15-bg: oklch(0.98 0.003 100);
  --color-tsl15-ink: #393d45;
  --color-tsl15-ink: oklch(0.26 0.015 265);
  --color-tsl15-mut: #7c8089;
  --color-tsl15-mut: oklch(0.55 0.012 265);
  --color-tsl15-line: #e6e7eb;
  --color-tsl15-line: oklch(0.91 0.006 265);
  --color-tsl15-accent: #c23d2e;
  --color-tsl15-accent: oklch(0.55 0.19 25);
  --font-tsl15-sans: 'Plus Jakarta Sans', system-ui, sans-serif;
}

.tsl-15 {
  width: 100%;
  height: 100svh;
  min-height: 100svh;
  color-scheme: light;
  interpolate-size: allow-keywords;
}
/* ::details-content has no variant, and interpolate-size is an inherited
   property set once — both are stylesheet concerns, not class-list ones. */

.tsl-15 details::details-content {
  height: 0;
  overflow: clip;
  transition: height .3s ease, content-visibility .3s allow-discrete;
}

.tsl-15 details[open]::details-content {
  height: auto;
}

@media (prefers-reduced-motion: reduce) {
  .tsl-15 details::details-content {
    transition: none;
  }
}
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=Plus+Jakarta+Sans:wght@400;500;600;700;800&family=JetBrains+Mono:wght@400;500;600&display=swap">

What changed in the port

Which parts became utilities, which stayed CSS, and why.

  • group-open:rotate-180 on the chevron is the port in miniature: the <details> declares group, the chevron declares what it does when the group opens, and details[open] summary svg disappears.
  • accent-tsl15-accent is worth calling out. A @theme colour mints the accent-color utility for free, so brand-coloured native checkboxes cost one class and keep every native behaviour.
  • UI change from the CSS original: every summary, checkbox label and the Clear-all button is now min-h-11 — filter rails are among the most-tapped UI on a phone and the original's 14px-padding rows were under target size.
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 E-Commerce Filter Sidebar with Native Details Accordion
Source: https://codefronts.com/layouts/tailwind-css-sidebar-layouts/tailwind-ecommerce-filter-sidebar-details-accordion/

A storefront filter rail built entirely on native <details>/<summary> &mdash; keyboard-operable, screen-reader-announced and crawlable with zero script. v4's open: variant styles the expanded state, and accent-color brands every checkbox in one utility.
## HTML
```html
<section class="tsl-15 w-full h-svh min-h-svh overflow-y-auto grid grid-cols-[250px_1fr] gap-7 p-7 font-tsl15-sans bg-tsl15-bg text-tsl15-ink">
  <aside aria-label="Product filters" class="sticky top-0 self-start max-h-[calc(100svh-3.5rem)] overflow-y-auto flex flex-col gap-1">
    <h2 class="flex justify-between items-baseline px-0.5 pt-1 pb-3.5 text-[15px] font-bold">Filters <button type="button" class="min-h-11 px-1 border-0 bg-transparent text-tsl15-accent text-[12.5px] font-medium underline underline-offset-[3px] cursor-pointer rounded focus-visible:outline-2 focus-visible:outline-tsl15-accent focus-visible:outline-offset-2">Clear all</button></h2>
    <details name="tsl15-filters" open class="group border-t border-tsl15-line">
      <summary class="flex items-center gap-2 min-h-11 px-0.5 text-[13.5px] font-semibold cursor-pointer list-none rounded-md [&amp;::-webkit-details-marker]:hidden focus-visible:outline-2 focus-visible:outline-tsl15-accent focus-visible:outline-offset-2">Category <span class="ml-auto text-[11.5px] font-medium text-tsl15-mut">128</span><svg viewBox="0 0 24 24" aria-hidden="true" class="w-4 h-4 fill-none stroke-tsl15-mut stroke-2 [stroke-linecap:round] [stroke-linejoin:round] transition-[rotate] duration-[250ms] group-open:rotate-180 motion-reduce:transition-none"><path d="m6 9 6 6 6-6"/></svg></summary>
      <div class="flex flex-col gap-2.5 px-0.5 pt-0.5 pb-4">
        <label class="flex items-center gap-2.5 min-h-11 text-[13.5px] cursor-pointer"><input type="checkbox" checked class="w-4 h-4 accent-tsl15-accent focus-visible:outline-2 focus-visible:outline-tsl15-accent focus-visible:outline-offset-2">Sneakers <span class="ml-auto text-[11.5px] text-tsl15-mut">64</span></label>
        <label class="flex items-center gap-2.5 min-h-11 text-[13.5px] cursor-pointer"><input type="checkbox" class="w-4 h-4 accent-tsl15-accent focus-visible:outline-2 focus-visible:outline-tsl15-accent focus-visible:outline-offset-2">Running <span class="ml-auto text-[11.5px] text-tsl15-mut">38</span></label>
        <label class="flex items-center gap-2.5 min-h-11 text-[13.5px] cursor-pointer"><input type="checkbox" class="w-4 h-4 accent-tsl15-accent focus-visible:outline-2 focus-visible:outline-tsl15-accent focus-visible:outline-offset-2">Trail <span class="ml-auto text-[11.5px] text-tsl15-mut">26</span></label>
      </div>
    </details>
    <details name="tsl15-filters" class="group border-t border-tsl15-line">
      <summary class="flex items-center gap-2 min-h-11 px-0.5 text-[13.5px] font-semibold cursor-pointer list-none rounded-md [&amp;::-webkit-details-marker]:hidden focus-visible:outline-2 focus-visible:outline-tsl15-accent focus-visible:outline-offset-2">Price <span class="ml-auto text-[11.5px] font-medium text-tsl15-mut">$40&ndash;220</span><svg viewBox="0 0 24 24" aria-hidden="true" class="w-4 h-4 fill-none stroke-tsl15-mut stroke-2 [stroke-linecap:round] [stroke-linejoin:round] transition-[rotate] duration-[250ms] group-open:rotate-180 motion-reduce:transition-none"><path d="m6 9 6 6 6-6"/></svg></summary>
      <div class="flex flex-col gap-2.5 px-0.5 pt-0.5 pb-4">
        <input type="range" min="40" max="220" value="120" aria-label="Maximum price" class="w-full accent-tsl15-accent focus-visible:outline-2 focus-visible:outline-tsl15-accent focus-visible:outline-offset-2">
        <label class="flex items-center gap-2.5 min-h-11 text-[13.5px] cursor-pointer"><input type="checkbox" class="w-4 h-4 accent-tsl15-accent focus-visible:outline-2 focus-visible:outline-tsl15-accent focus-visible:outline-offset-2">Under $80 <span class="ml-auto text-[11.5px] text-tsl15-mut">31</span></label>
        <label class="flex items-center gap-2.5 min-h-11 text-[13.5px] cursor-pointer"><input type="checkbox" class="w-4 h-4 accent-tsl15-accent focus-visible:outline-2 focus-visible:outline-tsl15-accent focus-visible:outline-offset-2">$80&ndash;$150 <span class="ml-auto text-[11.5px] text-tsl15-mut">57</span></label>
      </div>
    </details>
    <details name="tsl15-filters" class="group border-t border-tsl15-line">
      <summary class="flex items-center gap-2 min-h-11 px-0.5 text-[13.5px] font-semibold cursor-pointer list-none rounded-md [&amp;::-webkit-details-marker]:hidden focus-visible:outline-2 focus-visible:outline-tsl15-accent focus-visible:outline-offset-2">Brand <span class="ml-auto text-[11.5px] font-medium text-tsl15-mut">12</span><svg viewBox="0 0 24 24" aria-hidden="true" class="w-4 h-4 fill-none stroke-tsl15-mut stroke-2 [stroke-linecap:round] [stroke-linejoin:round] transition-[rotate] duration-[250ms] group-open:rotate-180 motion-reduce:transition-none"><path d="m6 9 6 6 6-6"/></svg></summary>
      <div class="flex flex-col gap-2.5 px-0.5 pt-0.5 pb-4">
        <label class="flex items-center gap-2.5 min-h-11 text-[13.5px] cursor-pointer"><input type="checkbox" class="w-4 h-4 accent-tsl15-accent focus-visible:outline-2 focus-visible:outline-tsl15-accent focus-visible:outline-offset-2">Veloce <span class="ml-auto text-[11.5px] text-tsl15-mut">44</span></label>
        <label class="flex items-center gap-2.5 min-h-11 text-[13.5px] cursor-pointer"><input type="checkbox" class="w-4 h-4 accent-tsl15-accent focus-visible:outline-2 focus-visible:outline-tsl15-accent focus-visible:outline-offset-2">Northpeak <span class="ml-auto text-[11.5px] text-tsl15-mut">29</span></label>
        <label class="flex items-center gap-2.5 min-h-11 text-[13.5px] cursor-pointer"><input type="checkbox" class="w-4 h-4 accent-tsl15-accent focus-visible:outline-2 focus-visible:outline-tsl15-accent focus-visible:outline-offset-2">Atlasform <span class="ml-auto text-[11.5px] text-tsl15-mut">18</span></label>
      </div>
    </details>
  </aside>
  <main aria-label="Products" class="grid grid-cols-[repeat(auto-fill,minmax(160px,1fr))] gap-[18px] content-start">
    <article><div class="aspect-square rounded-xl bg-[linear-gradient(135deg,oklch(0.93_0.01_265),oklch(0.88_0.015_265))]"></div><h3 class="mt-2.5 text-[13.5px] font-semibold leading-snug">Veloce Cloudrunner</h3><p class="mt-1 text-[13px] font-medium text-tsl15-mut">$128</p></article>
    <article><div class="aspect-square rounded-xl bg-[linear-gradient(135deg,oklch(0.93_0.01_265),oklch(0.88_0.015_265))]"></div><h3 class="mt-2.5 text-[13.5px] font-semibold leading-snug">Northpeak Trail 2</h3><p class="mt-1 text-[13px] font-medium text-tsl15-mut">$156</p></article>
    <article><div class="aspect-square rounded-xl bg-[linear-gradient(135deg,oklch(0.93_0.01_265),oklch(0.88_0.015_265))]"></div><h3 class="mt-2.5 text-[13.5px] font-semibold leading-snug">Atlasform Daily</h3><p class="mt-1 text-[13px] font-medium text-tsl15-mut">$92</p></article>
    <article><div class="aspect-square rounded-xl bg-[linear-gradient(135deg,oklch(0.93_0.01_265),oklch(0.88_0.015_265))]"></div><h3 class="mt-2.5 text-[13.5px] font-semibold leading-snug">Veloce Street LX</h3><p class="mt-1 text-[13px] font-medium text-tsl15-mut">$110</p></article>
  </main>
</section>
```
## CSS
```css
@import "tailwindcss";

@theme {
  --color-tsl15-bg: #fbfbf9;
  --color-tsl15-bg: oklch(0.98 0.003 100);
  --color-tsl15-ink: #393d45;
  --color-tsl15-ink: oklch(0.26 0.015 265);
  --color-tsl15-mut: #7c8089;
  --color-tsl15-mut: oklch(0.55 0.012 265);
  --color-tsl15-line: #e6e7eb;
  --color-tsl15-line: oklch(0.91 0.006 265);
  --color-tsl15-accent: #c23d2e;
  --color-tsl15-accent: oklch(0.55 0.19 25);
  --font-tsl15-sans: 'Plus Jakarta Sans', system-ui, sans-serif;
}

.tsl-15 {
  width: 100%;
  height: 100svh;
  min-height: 100svh;
  color-scheme: light;
  interpolate-size: allow-keywords;
}
/* ::details-content has no variant, and interpolate-size is an inherited
   property set once — both are stylesheet concerns, not class-list ones. */

.tsl-15 details::details-content {
  height: 0;
  overflow: clip;
  transition: height .3s ease, content-visibility .3s allow-discrete;
}

.tsl-15 details[open]::details-content {
  height: auto;
}

@media (prefers-reduced-motion: reduce) {
  .tsl-15 details::details-content {
    transition: none;
  }
}
```

How this works

The element choice buys the whole interaction budget. <details name="filters"> gives toggle-on-Enter/Space, an open attribute CSS can read, exclusive-accordion behaviour, and correct announcements — none of it authored. Tailwind's contribution is open:, which turns 'style the expanded state' into a prefix rather than a separate selector far from the summary.

The height animation stays half-CSS, honestly. interpolate-size: allow-keywords is an inherited property set once on the root; ::details-content is a pseudo-element with no variant. Both live in the stylesheet, and the markup keeps the parts that are design decisions — duration, easing, the open state.

Make it yours

  • Exclusive accordion: give every <details> the same name — still zero JS.
  • accent-* is the one-line brand pass; keep it on the range input too.
  • On mobile, wrap the rail in demo 10's popover drawer — the accordion markup does not change.

Gotchas — read before shipping

  • Never put links or buttons inside <summary> — the whole summary is one button and nested controls become unreachable.
  • interpolate-size is progressive enhancement (Chrome 129+). The accordion must work while snapping.
  • Sticky needs a scrolling ancestor and no overflow-hidden in the chain — the same trap as demo 07.

Browser support

ChromeSafariFirefoxEdge
129+17.4+130+129+

details/summary and sticky work back to 2020; the name attribute and the ::details-content height animation are 2024 enhancements that degrade silently.

Techniques used in this demo

Search CodeFronts

Loading…