15 / 30
All 30 in 30 Tailwind CSS Sidebar Layouts
- 01Tailwind SaaS Dashboard Sidebar with Native Dark Mode Switch
- 02Tailwind Collapsible Admin Sidebar with Icon Tooltips
- 03Tailwind Documentation Sidebar with Multi-Level :target Tree
- 04Tailwind Responsive Sidebar to Bottom Navigation Switch Layout
- 05Tailwind Analytics Sidebar with CSS Subgrid Column Alignment
- 06Tailwind Animated Collapsible Sidebar with Icon-Only Mode
- 07Tailwind Sticky Sidebar Layout with Scroll-Driven Progress Bar
- 08Tailwind Pure CSS Collapsible Sidebar Drawer without JavaScript
- 09Tailwind Fixed Sidebar Layout with Independently Scrolling Content
- 10Tailwind Off-Canvas Navigation Drawer with the Popover API
- 11Tailwind Right-Aligned Sidebar Layout for Inspector Panels
- 12Tailwind Two-Pane Webmail Layout with List and Reading Pane
- 13Tailwind Dual Sidebar App Shell with Left Nav and Context Panel
- 14Tailwind Mini Icon Rail Sidebar with Anchor-Positioned Active Pill
- 15Tailwind E-Commerce Filter Sidebar with Native Details Accordion
- 16Tailwind Floating Glassmorphism Sidebar with Gradient Hairline
- 17Tailwind Sidebar Menu with Pinned User Profile Footer
- 18Tailwind Push-Content Sidebar Drawer with GPU Transitions
- 19Tailwind Off-Canvas Cart Overlay with Blurred Backdrop Scrim
- 20Tailwind Sidebar with Persistent Collapsed State in localStorage
- 21Tailwind Sidebar with Sticky Search Bar Inside the Rail
- 22Tailwind Section-Grouped Sidebar Navigation with Header Labels
- 23Tailwind Sliding Active Indicator Sidebar with CSS :target
- 24Tailwind Multi-Level Nested Tree Sidebar with Details Branches
- 25Tailwind Tabbed Sidebar with Radio-Driven Panel Switching
- 26Tailwind Onboarding Wizard Sidebar with Step Progress Tracking
- 27Tailwind Resizable Sidebar Layout Using the CSS Resize Property
- 28Tailwind Three-Pane Workspace Shell with Icon Rail and List
- 29Tailwind Adaptive Sidebar Layout Using CSS Container Queries
- 30Tailwind Frosted Glass Floating Sidebar with Animated Aurora
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.
Mosaic by Cruip: a complete Tailwind admin dashboard template in HTML, React, Next.js and Vue · $69
Cruip · Mosaic by Cruip · Affiliate link
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 [&::-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 [&::-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–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–$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 [&::-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><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 [&::-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 [&::-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–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–$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 [&::-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;
}
}@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.
<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-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;
}
}@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;
}
}<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">
<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-180on the chevron is the port in miniature: the<details>declaresgroup, the chevron declares what it does when the group opens, anddetails[open] summary svgdisappears.accent-tsl15-accentis worth calling out. A@themecolour 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.
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> — 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 [&::-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 [&::-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–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–$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 [&::-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;
}
}
```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> — 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 [&::-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 [&::-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–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–$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 [&::-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 samename— 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-sizeis progressive enhancement (Chrome 129+). The accordion must work while snapping.- Sticky needs a scrolling ancestor and no
overflow-hiddenin the chain — the same trap as demo 07.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 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.