19 / 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 Off-Canvas Cart Overlay with Blurred Backdrop Scrim
The modal-grade overlay drawer: content dims and blurs behind a scrim, the panel lifts on a shadow that fades in with the slide, and pointer-events discipline keeps the dimmed page genuinely inert. A cart, because that is the pattern's home.
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-19 relative w-full h-svh min-h-svh grid grid-rows-[auto_1fr] overflow-hidden font-tsl19-sans bg-tsl19-bg text-tsl19-ink">
<input type="checkbox" id="tsl19-o" class="sr-only peer">
<header class="flex items-center justify-between h-14 px-5 bg-white border-b border-tsl19-line text-[15px] font-bold">
<strong>Alpine Supply Co.</strong>
<label for="tsl19-o" class="inline-flex items-center gap-2.5 min-h-11 px-3.5 rounded-[10px] border border-tsl19-line text-[13px] font-semibold cursor-pointer transition-colors duration-200 hover:bg-tsl19-hover"><svg viewBox="0 0 24 24" aria-hidden="true" class="w-[17px] h-[17px] fill-none stroke-current stroke-[1.9] [stroke-linecap:round] [stroke-linejoin:round]"><circle cx="9" cy="21" r="1"/><circle cx="20" cy="21" r="1"/><path d="M1 1h4l2.68 13.39a2 2 0 0 0 2 1.61h9.72a2 2 0 0 0 2-1.61L23 6H6"/></svg>Cart · 2</label>
</header>
<main class="p-[26px] overflow-y-auto [scrollbar-gutter:stable]">
<h1 class="mb-[18px] text-[21px] font-bold leading-tight">New arrivals</h1>
<div class="grid grid-cols-[repeat(auto-fill,minmax(140px,1fr))] gap-3.5">
<div class="aspect-[3/4] rounded-xl bg-[linear-gradient(150deg,oklch(0.93_0.01_145),oklch(0.87_0.015_145))]"></div>
<div class="aspect-[3/4] rounded-xl bg-[linear-gradient(150deg,oklch(0.93_0.01_145),oklch(0.87_0.015_145))]"></div>
<div class="aspect-[3/4] rounded-xl bg-[linear-gradient(150deg,oklch(0.93_0.01_145),oklch(0.87_0.015_145))]"></div>
<div class="aspect-[3/4] rounded-xl bg-[linear-gradient(150deg,oklch(0.93_0.01_145),oklch(0.87_0.015_145))]"></div>
<div class="aspect-[3/4] rounded-xl bg-[linear-gradient(150deg,oklch(0.93_0.01_145),oklch(0.87_0.015_145))]"></div>
<div class="aspect-[3/4] rounded-xl bg-[linear-gradient(150deg,oklch(0.93_0.01_145),oklch(0.87_0.015_145))]"></div>
</div>
</main>
<label for="tsl19-o" aria-hidden="true" class="tsl-19-scrim absolute inset-0 z-[3] bg-[oklch(0_0_0/0.45)] backdrop-blur-[4px] opacity-0 pointer-events-none transition-opacity duration-300 motion-reduce:transition-none"></label>
<aside aria-label="Shopping cart" class="tsl-19-cart absolute inset-y-0 right-0 z-[4] flex flex-col w-[min(340px,92vw)] p-[18px] bg-white border-l border-tsl19-line translate-x-full transition-[translate,box-shadow] duration-[320ms] ease-[cubic-bezier(.4,0,.2,1)] motion-reduce:transition-none">
<div class="flex items-center justify-between pb-4">
<h2 class="text-base font-bold">Your cart</h2>
<label for="tsl19-o" aria-label="Close cart" class="grid place-items-center w-11 h-11 rounded-[9px] text-tsl19-mut cursor-pointer transition-colors duration-200 hover:text-tsl19-ink hover:bg-tsl19-hover"><svg viewBox="0 0 24 24" aria-hidden="true" class="w-[17px] h-[17px] fill-none stroke-current stroke-[1.9] [stroke-linecap:round]"><path d="M6 6l12 12M18 6 6 18"/></svg></label>
</div>
<div class="grid grid-cols-[auto_1fr_auto] gap-3 items-center py-3 border-t border-tsl19-line"><span aria-hidden="true" class="w-[52px] h-[52px] rounded-[10px] bg-[linear-gradient(150deg,oklch(0.9_0.012_145),oklch(0.84_0.018_145))]"></span><span><strong class="block text-[13.5px] font-semibold leading-snug">Ridge shell jacket</strong><small class="text-xs leading-snug text-tsl19-mut">Moss · M</small></span><data class="text-[13.5px] font-semibold tabular-nums">$168</data></div>
<div class="grid grid-cols-[auto_1fr_auto] gap-3 items-center py-3 border-t border-tsl19-line"><span aria-hidden="true" class="w-[52px] h-[52px] rounded-[10px] bg-[linear-gradient(150deg,oklch(0.9_0.012_145),oklch(0.84_0.018_145))]"></span><span><strong class="block text-[13.5px] font-semibold leading-snug">Trail merino crew</strong><small class="text-xs leading-snug text-tsl19-mut">Ash · L</small></span><data class="text-[13.5px] font-semibold tabular-nums">$74</data></div>
<div class="mt-auto grid grid-cols-[1fr_auto] items-center gap-3.5 pt-4 border-t border-tsl19-line text-sm font-medium text-tsl19-mut">
<span>Subtotal</span><data class="text-[13.5px] font-semibold tabular-nums text-tsl19-ink">$242</data>
<button type="button" class="col-span-full min-h-12 rounded-[11px] border-0 bg-tsl19-accent text-white text-sm font-bold cursor-pointer transition-[filter] duration-200 hover:brightness-110 focus-visible:outline-2 focus-visible:outline-tsl19-accent focus-visible:outline-offset-2">Checkout</button>
</div>
</aside>
</section><section class="tsl-19 relative w-full h-svh min-h-svh grid grid-rows-[auto_1fr] overflow-hidden font-tsl19-sans bg-tsl19-bg text-tsl19-ink">
<input type="checkbox" id="tsl19-o" class="sr-only peer">
<header class="flex items-center justify-between h-14 px-5 bg-white border-b border-tsl19-line text-[15px] font-bold">
<strong>Alpine Supply Co.</strong>
<label for="tsl19-o" class="inline-flex items-center gap-2.5 min-h-11 px-3.5 rounded-[10px] border border-tsl19-line text-[13px] font-semibold cursor-pointer transition-colors duration-200 hover:bg-tsl19-hover"><svg viewBox="0 0 24 24" aria-hidden="true" class="w-[17px] h-[17px] fill-none stroke-current stroke-[1.9] [stroke-linecap:round] [stroke-linejoin:round]"><circle cx="9" cy="21" r="1"/><circle cx="20" cy="21" r="1"/><path d="M1 1h4l2.68 13.39a2 2 0 0 0 2 1.61h9.72a2 2 0 0 0 2-1.61L23 6H6"/></svg>Cart · 2</label>
</header>
<main class="p-[26px] overflow-y-auto [scrollbar-gutter:stable]">
<h1 class="mb-[18px] text-[21px] font-bold leading-tight">New arrivals</h1>
<div class="grid grid-cols-[repeat(auto-fill,minmax(140px,1fr))] gap-3.5">
<div class="aspect-[3/4] rounded-xl bg-[linear-gradient(150deg,oklch(0.93_0.01_145),oklch(0.87_0.015_145))]"></div>
<div class="aspect-[3/4] rounded-xl bg-[linear-gradient(150deg,oklch(0.93_0.01_145),oklch(0.87_0.015_145))]"></div>
<div class="aspect-[3/4] rounded-xl bg-[linear-gradient(150deg,oklch(0.93_0.01_145),oklch(0.87_0.015_145))]"></div>
<div class="aspect-[3/4] rounded-xl bg-[linear-gradient(150deg,oklch(0.93_0.01_145),oklch(0.87_0.015_145))]"></div>
<div class="aspect-[3/4] rounded-xl bg-[linear-gradient(150deg,oklch(0.93_0.01_145),oklch(0.87_0.015_145))]"></div>
<div class="aspect-[3/4] rounded-xl bg-[linear-gradient(150deg,oklch(0.93_0.01_145),oklch(0.87_0.015_145))]"></div>
</div>
</main>
<label for="tsl19-o" aria-hidden="true" class="tsl-19-scrim absolute inset-0 z-[3] bg-[oklch(0_0_0/0.45)] backdrop-blur-[4px] opacity-0 pointer-events-none transition-opacity duration-300 motion-reduce:transition-none"></label>
<aside aria-label="Shopping cart" class="tsl-19-cart absolute inset-y-0 right-0 z-[4] flex flex-col w-[min(340px,92vw)] p-[18px] bg-white border-l border-tsl19-line translate-x-full transition-[translate,box-shadow] duration-[320ms] ease-[cubic-bezier(.4,0,.2,1)] motion-reduce:transition-none">
<div class="flex items-center justify-between pb-4">
<h2 class="text-base font-bold">Your cart</h2>
<label for="tsl19-o" aria-label="Close cart" class="grid place-items-center w-11 h-11 rounded-[9px] text-tsl19-mut cursor-pointer transition-colors duration-200 hover:text-tsl19-ink hover:bg-tsl19-hover"><svg viewBox="0 0 24 24" aria-hidden="true" class="w-[17px] h-[17px] fill-none stroke-current stroke-[1.9] [stroke-linecap:round]"><path d="M6 6l12 12M18 6 6 18"/></svg></label>
</div>
<div class="grid grid-cols-[auto_1fr_auto] gap-3 items-center py-3 border-t border-tsl19-line"><span aria-hidden="true" class="w-[52px] h-[52px] rounded-[10px] bg-[linear-gradient(150deg,oklch(0.9_0.012_145),oklch(0.84_0.018_145))]"></span><span><strong class="block text-[13.5px] font-semibold leading-snug">Ridge shell jacket</strong><small class="text-xs leading-snug text-tsl19-mut">Moss · M</small></span><data class="text-[13.5px] font-semibold tabular-nums">$168</data></div>
<div class="grid grid-cols-[auto_1fr_auto] gap-3 items-center py-3 border-t border-tsl19-line"><span aria-hidden="true" class="w-[52px] h-[52px] rounded-[10px] bg-[linear-gradient(150deg,oklch(0.9_0.012_145),oklch(0.84_0.018_145))]"></span><span><strong class="block text-[13.5px] font-semibold leading-snug">Trail merino crew</strong><small class="text-xs leading-snug text-tsl19-mut">Ash · L</small></span><data class="text-[13.5px] font-semibold tabular-nums">$74</data></div>
<div class="mt-auto grid grid-cols-[1fr_auto] items-center gap-3.5 pt-4 border-t border-tsl19-line text-sm font-medium text-tsl19-mut">
<span>Subtotal</span><data class="text-[13.5px] font-semibold tabular-nums text-tsl19-ink">$242</data>
<button type="button" class="col-span-full min-h-12 rounded-[11px] border-0 bg-tsl19-accent text-white text-sm font-bold cursor-pointer transition-[filter] duration-200 hover:brightness-110 focus-visible:outline-2 focus-visible:outline-tsl19-accent focus-visible:outline-offset-2">Checkout</button>
</div>
</aside>
</section>@import "tailwindcss";
@theme {
--color-tsl19-bg: #f8faf7;
--color-tsl19-bg: oklch(0.975 0.004 120);
--color-tsl19-ink: #383f3a;
--color-tsl19-ink: oklch(0.26 0.015 145);
--color-tsl19-mut: #767e78;
--color-tsl19-mut: oklch(0.52 0.012 145);
--color-tsl19-line: #e0e5e1;
--color-tsl19-line: oklch(0.9 0.008 145);
--color-tsl19-accent: #2f7a52;
--color-tsl19-accent: oklch(0.45 0.12 150);
--color-tsl19-hover: rgb(56 63 58 / 0.05);
--color-tsl19-hover: color-mix(in oklab, oklch(0.26 0.015 145) 5%, transparent);
--font-tsl19-sans: 'Plus Jakarta Sans', system-ui, sans-serif;
}
.tsl-19 {
width: 100%;
height: 100svh;
min-height: 100svh;
color-scheme: light;
}
/* STATE — opacity transitions, pointer-events flips instantly, so a
half-faded scrim is never clickable. */
#tsl19-o:checked ~ .tsl-19-scrim {
opacity: 1;
pointer-events: auto;
}
#tsl19-o:checked ~ .tsl-19-cart {
translate: 0;
box-shadow: -16px 0 48px oklch(0 0 0 / 0.18);
}
#tsl19-o:focus-visible ~ header label[for="tsl19-o"] {
outline: 2px solid var(--color-tsl19-accent);
outline-offset: 2px;
}@import "tailwindcss";
@theme {
--color-tsl19-bg: #f8faf7;
--color-tsl19-bg: oklch(0.975 0.004 120);
--color-tsl19-ink: #383f3a;
--color-tsl19-ink: oklch(0.26 0.015 145);
--color-tsl19-mut: #767e78;
--color-tsl19-mut: oklch(0.52 0.012 145);
--color-tsl19-line: #e0e5e1;
--color-tsl19-line: oklch(0.9 0.008 145);
--color-tsl19-accent: #2f7a52;
--color-tsl19-accent: oklch(0.45 0.12 150);
--color-tsl19-hover: rgb(56 63 58 / 0.05);
--color-tsl19-hover: color-mix(in oklab, oklch(0.26 0.015 145) 5%, transparent);
--font-tsl19-sans: 'Plus Jakarta Sans', system-ui, sans-serif;
}
.tsl-19 {
width: 100%;
height: 100svh;
min-height: 100svh;
color-scheme: light;
}
/* STATE — opacity transitions, pointer-events flips instantly, so a
half-faded scrim is never clickable. */
#tsl19-o:checked ~ .tsl-19-scrim {
opacity: 1;
pointer-events: auto;
}
#tsl19-o:checked ~ .tsl-19-cart {
translate: 0;
box-shadow: -16px 0 48px oklch(0 0 0 / 0.18);
}
#tsl19-o:focus-visible ~ header label[for="tsl19-o"] {
outline: 2px solid var(--color-tsl19-accent);
outline-offset: 2px;
}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-tsl19-bg: #f8faf7;
--color-tsl19-bg: oklch(0.975 0.004 120);
--color-tsl19-ink: #383f3a;
--color-tsl19-ink: oklch(0.26 0.015 145);
--color-tsl19-mut: #767e78;
--color-tsl19-mut: oklch(0.52 0.012 145);
--color-tsl19-line: #e0e5e1;
--color-tsl19-line: oklch(0.9 0.008 145);
--color-tsl19-accent: #2f7a52;
--color-tsl19-accent: oklch(0.45 0.12 150);
--color-tsl19-hover: rgb(56 63 58 / 0.05);
--color-tsl19-hover: color-mix(in oklab, oklch(0.26 0.015 145) 5%, transparent);
--font-tsl19-sans: 'Plus Jakarta Sans', system-ui, sans-serif;
}
.tsl-19 {
width: 100%;
height: 100svh;
min-height: 100svh;
color-scheme: light;
}
/* STATE — opacity transitions, pointer-events flips instantly, so a
half-faded scrim is never clickable. */
#tsl19-o:checked ~ .tsl-19-scrim {
opacity: 1;
pointer-events: auto;
}
#tsl19-o:checked ~ .tsl-19-cart {
translate: 0;
box-shadow: -16px 0 48px oklch(0 0 0 / 0.18);
}
#tsl19-o:focus-visible ~ header label[for="tsl19-o"] {
outline: 2px solid var(--color-tsl19-accent);
outline-offset: 2px;
}@import "tailwindcss";
@theme {
--color-tsl19-bg: #f8faf7;
--color-tsl19-bg: oklch(0.975 0.004 120);
--color-tsl19-ink: #383f3a;
--color-tsl19-ink: oklch(0.26 0.015 145);
--color-tsl19-mut: #767e78;
--color-tsl19-mut: oklch(0.52 0.012 145);
--color-tsl19-line: #e0e5e1;
--color-tsl19-line: oklch(0.9 0.008 145);
--color-tsl19-accent: #2f7a52;
--color-tsl19-accent: oklch(0.45 0.12 150);
--color-tsl19-hover: rgb(56 63 58 / 0.05);
--color-tsl19-hover: color-mix(in oklab, oklch(0.26 0.015 145) 5%, transparent);
--font-tsl19-sans: 'Plus Jakarta Sans', system-ui, sans-serif;
}
.tsl-19 {
width: 100%;
height: 100svh;
min-height: 100svh;
color-scheme: light;
}
/* STATE — opacity transitions, pointer-events flips instantly, so a
half-faded scrim is never clickable. */
#tsl19-o:checked ~ .tsl-19-scrim {
opacity: 1;
pointer-events: auto;
}
#tsl19-o:checked ~ .tsl-19-cart {
translate: 0;
box-shadow: -16px 0 48px oklch(0 0 0 / 0.18);
}
#tsl19-o:focus-visible ~ header label[for="tsl19-o"] {
outline: 2px solid var(--color-tsl19-accent);
outline-offset: 2px;
}<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.
- Pairing
opacitywithpointer-eventsas twohas-checked:utilities on the same element is the strongest argument for variants in this whole collection: the bug this pattern usually ships with (an invisible scrim that still eats clicks) becomes visible as a missing class. - UI change from the CSS original: the close control is 44px rather than 34px, the checkout button is
min-h-12, and totals usetabular-numsso quantities and prices stay aligned as the cart changes.
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 Off-Canvas Cart Overlay with Blurred Backdrop Scrim
Source: https://codefronts.com/layouts/tailwind-css-sidebar-layouts/tailwind-off-canvas-cart-overlay-blurred-backdrop/
The modal-grade overlay drawer: content dims and blurs behind a scrim, the panel lifts on a shadow that fades in with the slide, and pointer-events discipline keeps the dimmed page genuinely inert. A cart, because that is the pattern's home.
## HTML
```html
<section class="tsl-19 relative w-full h-svh min-h-svh grid grid-rows-[auto_1fr] overflow-hidden font-tsl19-sans bg-tsl19-bg text-tsl19-ink">
<input type="checkbox" id="tsl19-o" class="sr-only peer">
<header class="flex items-center justify-between h-14 px-5 bg-white border-b border-tsl19-line text-[15px] font-bold">
<strong>Alpine Supply Co.</strong>
<label for="tsl19-o" class="inline-flex items-center gap-2.5 min-h-11 px-3.5 rounded-[10px] border border-tsl19-line text-[13px] font-semibold cursor-pointer transition-colors duration-200 hover:bg-tsl19-hover"><svg viewBox="0 0 24 24" aria-hidden="true" class="w-[17px] h-[17px] fill-none stroke-current stroke-[1.9] [stroke-linecap:round] [stroke-linejoin:round]"><circle cx="9" cy="21" r="1"/><circle cx="20" cy="21" r="1"/><path d="M1 1h4l2.68 13.39a2 2 0 0 0 2 1.61h9.72a2 2 0 0 0 2-1.61L23 6H6"/></svg>Cart · 2</label>
</header>
<main class="p-[26px] overflow-y-auto [scrollbar-gutter:stable]">
<h1 class="mb-[18px] text-[21px] font-bold leading-tight">New arrivals</h1>
<div class="grid grid-cols-[repeat(auto-fill,minmax(140px,1fr))] gap-3.5">
<div class="aspect-[3/4] rounded-xl bg-[linear-gradient(150deg,oklch(0.93_0.01_145),oklch(0.87_0.015_145))]"></div>
<div class="aspect-[3/4] rounded-xl bg-[linear-gradient(150deg,oklch(0.93_0.01_145),oklch(0.87_0.015_145))]"></div>
<div class="aspect-[3/4] rounded-xl bg-[linear-gradient(150deg,oklch(0.93_0.01_145),oklch(0.87_0.015_145))]"></div>
<div class="aspect-[3/4] rounded-xl bg-[linear-gradient(150deg,oklch(0.93_0.01_145),oklch(0.87_0.015_145))]"></div>
<div class="aspect-[3/4] rounded-xl bg-[linear-gradient(150deg,oklch(0.93_0.01_145),oklch(0.87_0.015_145))]"></div>
<div class="aspect-[3/4] rounded-xl bg-[linear-gradient(150deg,oklch(0.93_0.01_145),oklch(0.87_0.015_145))]"></div>
</div>
</main>
<label for="tsl19-o" aria-hidden="true" class="tsl-19-scrim absolute inset-0 z-[3] bg-[oklch(0_0_0/0.45)] backdrop-blur-[4px] opacity-0 pointer-events-none transition-opacity duration-300 motion-reduce:transition-none"></label>
<aside aria-label="Shopping cart" class="tsl-19-cart absolute inset-y-0 right-0 z-[4] flex flex-col w-[min(340px,92vw)] p-[18px] bg-white border-l border-tsl19-line translate-x-full transition-[translate,box-shadow] duration-[320ms] ease-[cubic-bezier(.4,0,.2,1)] motion-reduce:transition-none">
<div class="flex items-center justify-between pb-4">
<h2 class="text-base font-bold">Your cart</h2>
<label for="tsl19-o" aria-label="Close cart" class="grid place-items-center w-11 h-11 rounded-[9px] text-tsl19-mut cursor-pointer transition-colors duration-200 hover:text-tsl19-ink hover:bg-tsl19-hover"><svg viewBox="0 0 24 24" aria-hidden="true" class="w-[17px] h-[17px] fill-none stroke-current stroke-[1.9] [stroke-linecap:round]"><path d="M6 6l12 12M18 6 6 18"/></svg></label>
</div>
<div class="grid grid-cols-[auto_1fr_auto] gap-3 items-center py-3 border-t border-tsl19-line"><span aria-hidden="true" class="w-[52px] h-[52px] rounded-[10px] bg-[linear-gradient(150deg,oklch(0.9_0.012_145),oklch(0.84_0.018_145))]"></span><span><strong class="block text-[13.5px] font-semibold leading-snug">Ridge shell jacket</strong><small class="text-xs leading-snug text-tsl19-mut">Moss · M</small></span><data class="text-[13.5px] font-semibold tabular-nums">$168</data></div>
<div class="grid grid-cols-[auto_1fr_auto] gap-3 items-center py-3 border-t border-tsl19-line"><span aria-hidden="true" class="w-[52px] h-[52px] rounded-[10px] bg-[linear-gradient(150deg,oklch(0.9_0.012_145),oklch(0.84_0.018_145))]"></span><span><strong class="block text-[13.5px] font-semibold leading-snug">Trail merino crew</strong><small class="text-xs leading-snug text-tsl19-mut">Ash · L</small></span><data class="text-[13.5px] font-semibold tabular-nums">$74</data></div>
<div class="mt-auto grid grid-cols-[1fr_auto] items-center gap-3.5 pt-4 border-t border-tsl19-line text-sm font-medium text-tsl19-mut">
<span>Subtotal</span><data class="text-[13.5px] font-semibold tabular-nums text-tsl19-ink">$242</data>
<button type="button" class="col-span-full min-h-12 rounded-[11px] border-0 bg-tsl19-accent text-white text-sm font-bold cursor-pointer transition-[filter] duration-200 hover:brightness-110 focus-visible:outline-2 focus-visible:outline-tsl19-accent focus-visible:outline-offset-2">Checkout</button>
</div>
</aside>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tsl19-bg: #f8faf7;
--color-tsl19-bg: oklch(0.975 0.004 120);
--color-tsl19-ink: #383f3a;
--color-tsl19-ink: oklch(0.26 0.015 145);
--color-tsl19-mut: #767e78;
--color-tsl19-mut: oklch(0.52 0.012 145);
--color-tsl19-line: #e0e5e1;
--color-tsl19-line: oklch(0.9 0.008 145);
--color-tsl19-accent: #2f7a52;
--color-tsl19-accent: oklch(0.45 0.12 150);
--color-tsl19-hover: rgb(56 63 58 / 0.05);
--color-tsl19-hover: color-mix(in oklab, oklch(0.26 0.015 145) 5%, transparent);
--font-tsl19-sans: 'Plus Jakarta Sans', system-ui, sans-serif;
}
.tsl-19 {
width: 100%;
height: 100svh;
min-height: 100svh;
color-scheme: light;
}
/* STATE — opacity transitions, pointer-events flips instantly, so a
half-faded scrim is never clickable. */
#tsl19-o:checked ~ .tsl-19-scrim {
opacity: 1;
pointer-events: auto;
}
#tsl19-o:checked ~ .tsl-19-cart {
translate: 0;
box-shadow: -16px 0 48px oklch(0 0 0 / 0.18);
}
#tsl19-o:focus-visible ~ header label[for="tsl19-o"] {
outline: 2px solid var(--color-tsl19-accent);
outline-offset: 2px;
}
```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 Off-Canvas Cart Overlay with Blurred Backdrop Scrim
Source: https://codefronts.com/layouts/tailwind-css-sidebar-layouts/tailwind-off-canvas-cart-overlay-blurred-backdrop/
The modal-grade overlay drawer: content dims and blurs behind a scrim, the panel lifts on a shadow that fades in with the slide, and pointer-events discipline keeps the dimmed page genuinely inert. A cart, because that is the pattern's home.
## HTML
```html
<section class="tsl-19 relative w-full h-svh min-h-svh grid grid-rows-[auto_1fr] overflow-hidden font-tsl19-sans bg-tsl19-bg text-tsl19-ink">
<input type="checkbox" id="tsl19-o" class="sr-only peer">
<header class="flex items-center justify-between h-14 px-5 bg-white border-b border-tsl19-line text-[15px] font-bold">
<strong>Alpine Supply Co.</strong>
<label for="tsl19-o" class="inline-flex items-center gap-2.5 min-h-11 px-3.5 rounded-[10px] border border-tsl19-line text-[13px] font-semibold cursor-pointer transition-colors duration-200 hover:bg-tsl19-hover"><svg viewBox="0 0 24 24" aria-hidden="true" class="w-[17px] h-[17px] fill-none stroke-current stroke-[1.9] [stroke-linecap:round] [stroke-linejoin:round]"><circle cx="9" cy="21" r="1"/><circle cx="20" cy="21" r="1"/><path d="M1 1h4l2.68 13.39a2 2 0 0 0 2 1.61h9.72a2 2 0 0 0 2-1.61L23 6H6"/></svg>Cart · 2</label>
</header>
<main class="p-[26px] overflow-y-auto [scrollbar-gutter:stable]">
<h1 class="mb-[18px] text-[21px] font-bold leading-tight">New arrivals</h1>
<div class="grid grid-cols-[repeat(auto-fill,minmax(140px,1fr))] gap-3.5">
<div class="aspect-[3/4] rounded-xl bg-[linear-gradient(150deg,oklch(0.93_0.01_145),oklch(0.87_0.015_145))]"></div>
<div class="aspect-[3/4] rounded-xl bg-[linear-gradient(150deg,oklch(0.93_0.01_145),oklch(0.87_0.015_145))]"></div>
<div class="aspect-[3/4] rounded-xl bg-[linear-gradient(150deg,oklch(0.93_0.01_145),oklch(0.87_0.015_145))]"></div>
<div class="aspect-[3/4] rounded-xl bg-[linear-gradient(150deg,oklch(0.93_0.01_145),oklch(0.87_0.015_145))]"></div>
<div class="aspect-[3/4] rounded-xl bg-[linear-gradient(150deg,oklch(0.93_0.01_145),oklch(0.87_0.015_145))]"></div>
<div class="aspect-[3/4] rounded-xl bg-[linear-gradient(150deg,oklch(0.93_0.01_145),oklch(0.87_0.015_145))]"></div>
</div>
</main>
<label for="tsl19-o" aria-hidden="true" class="tsl-19-scrim absolute inset-0 z-[3] bg-[oklch(0_0_0/0.45)] backdrop-blur-[4px] opacity-0 pointer-events-none transition-opacity duration-300 motion-reduce:transition-none"></label>
<aside aria-label="Shopping cart" class="tsl-19-cart absolute inset-y-0 right-0 z-[4] flex flex-col w-[min(340px,92vw)] p-[18px] bg-white border-l border-tsl19-line translate-x-full transition-[translate,box-shadow] duration-[320ms] ease-[cubic-bezier(.4,0,.2,1)] motion-reduce:transition-none">
<div class="flex items-center justify-between pb-4">
<h2 class="text-base font-bold">Your cart</h2>
<label for="tsl19-o" aria-label="Close cart" class="grid place-items-center w-11 h-11 rounded-[9px] text-tsl19-mut cursor-pointer transition-colors duration-200 hover:text-tsl19-ink hover:bg-tsl19-hover"><svg viewBox="0 0 24 24" aria-hidden="true" class="w-[17px] h-[17px] fill-none stroke-current stroke-[1.9] [stroke-linecap:round]"><path d="M6 6l12 12M18 6 6 18"/></svg></label>
</div>
<div class="grid grid-cols-[auto_1fr_auto] gap-3 items-center py-3 border-t border-tsl19-line"><span aria-hidden="true" class="w-[52px] h-[52px] rounded-[10px] bg-[linear-gradient(150deg,oklch(0.9_0.012_145),oklch(0.84_0.018_145))]"></span><span><strong class="block text-[13.5px] font-semibold leading-snug">Ridge shell jacket</strong><small class="text-xs leading-snug text-tsl19-mut">Moss · M</small></span><data class="text-[13.5px] font-semibold tabular-nums">$168</data></div>
<div class="grid grid-cols-[auto_1fr_auto] gap-3 items-center py-3 border-t border-tsl19-line"><span aria-hidden="true" class="w-[52px] h-[52px] rounded-[10px] bg-[linear-gradient(150deg,oklch(0.9_0.012_145),oklch(0.84_0.018_145))]"></span><span><strong class="block text-[13.5px] font-semibold leading-snug">Trail merino crew</strong><small class="text-xs leading-snug text-tsl19-mut">Ash · L</small></span><data class="text-[13.5px] font-semibold tabular-nums">$74</data></div>
<div class="mt-auto grid grid-cols-[1fr_auto] items-center gap-3.5 pt-4 border-t border-tsl19-line text-sm font-medium text-tsl19-mut">
<span>Subtotal</span><data class="text-[13.5px] font-semibold tabular-nums text-tsl19-ink">$242</data>
<button type="button" class="col-span-full min-h-12 rounded-[11px] border-0 bg-tsl19-accent text-white text-sm font-bold cursor-pointer transition-[filter] duration-200 hover:brightness-110 focus-visible:outline-2 focus-visible:outline-tsl19-accent focus-visible:outline-offset-2">Checkout</button>
</div>
</aside>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tsl19-bg: #f8faf7;
--color-tsl19-bg: oklch(0.975 0.004 120);
--color-tsl19-ink: #383f3a;
--color-tsl19-ink: oklch(0.26 0.015 145);
--color-tsl19-mut: #767e78;
--color-tsl19-mut: oklch(0.52 0.012 145);
--color-tsl19-line: #e0e5e1;
--color-tsl19-line: oklch(0.9 0.008 145);
--color-tsl19-accent: #2f7a52;
--color-tsl19-accent: oklch(0.45 0.12 150);
--color-tsl19-hover: rgb(56 63 58 / 0.05);
--color-tsl19-hover: color-mix(in oklab, oklch(0.26 0.015 145) 5%, transparent);
--font-tsl19-sans: 'Plus Jakarta Sans', system-ui, sans-serif;
}
.tsl-19 {
width: 100%;
height: 100svh;
min-height: 100svh;
color-scheme: light;
}
/* STATE — opacity transitions, pointer-events flips instantly, so a
half-faded scrim is never clickable. */
#tsl19-o:checked ~ .tsl-19-scrim {
opacity: 1;
pointer-events: auto;
}
#tsl19-o:checked ~ .tsl-19-cart {
translate: 0;
box-shadow: -16px 0 48px oklch(0 0 0 / 0.18);
}
#tsl19-o:focus-visible ~ header label[for="tsl19-o"] {
outline: 2px solid var(--color-tsl19-accent);
outline-offset: 2px;
}
```How this works
Two properties carry the whole scrim. opacity transitions (never display, which cannot tween) and pointer-events flips instantly, so a half-faded scrim is never clickable. Both states sit on one element as a has-checked: pair, which is the clearest possible statement of 'resting' versus 'open'.
Right-hand slide is the convention for carts and settings, as left is for navigation. The drawer moves on translate-x only; the shadow is a second animated property on the same 320ms curve.
Make it yours
- Real modality in six lines: swap the aside for
<dialog>+showModal(), or use demo 10's popover — both bring focus trapping. - Blur strength: 4px hints, 12px insists. Full-viewport blur is expensive; test on integrated graphics.
- Curtain choreography: add
has-checked:delay-[80ms]to the drawer so the scrim starts fading first.
Gotchas — read before shipping
- Pure-CSS overlays do NOT trap focus — keyboard users can tab into the dimmed page. Fine for a demo, not for checkout.
- A full-viewport
backdrop-bluris the most expensive effect in this collection. Consider dropping the blur underprefers-reduced-transparency. pointer-events-noneon the RESTING scrim is mandatory; an invisible scrim eating every click is a classic shipped bug.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 111+ | 16.4+ | 128+ | 111+ |
:has() and backdrop-filter are both Baseline; where backdrop-filter is missing the dim survives on its own.