14 / 20
All 20 in 20 Tailwind CSS Sidebars
- 01Tailwind Accessible Sidebar Navigation ARIA Reference
- 02Tailwind Sidebar Focus Trap and Restore on Close
- 03Tailwind Inert Background Content Behind a Drawer
- 04Tailwind Sidebar Navigation Is Not a Tab List
- 05Tailwind Announcing Collapsed and Expanded Sidebar State
- 06Tailwind Roving Tabindex for Sidebar Keyboard Navigation
- 07Tailwind Persisting Sidebar Collapse State Across Reloads
- 08Tailwind Sidebar Scroll Containment with Overscroll Behavior
- 09Tailwind Nested Submenu Keyboard and Screen Reader Behavior
- 10Tailwind Resizable Sidebar with a Keyboard Accessible Handle
- 11Pure Tailwind Collapsible Sidebar with Checkbox State
- 12Tailwind Responsive Sidebar Breakpoint Behavior
- 13Pure Tailwind Icon Rail Sidebar with Accessible Labels
- 14Tailwind Dashboard Sidebar with Current Page State
- 15Pure Tailwind Multi Level Sidebar Menu Disclosure Pattern
- 16Pure Tailwind Accordion Sidebar with Details and Summary
- 17Pure Tailwind Sticky Full Height Sidebar Layout Mechanics
- 18Pure Tailwind Floating Sidebar Stacking and Overlay Order
- 19Tailwind Off Canvas Sidebar Drawer with Focus Return
- 20Pure Tailwind Sidebar Footer Pinning with Scrollable Nav
Tailwind Dashboard Sidebar with Current Page State
Where the user is has to be answered three times in an admin shell — in the rail, in the group that contains the page, and in the breadcrumb — and all three have to agree. This build derives every one of them from aria-current="page" on a single link: the item marker through aria-[current=page]:, the group badge through group-has-[…]:, and the breadcrumb from the same word in the copy.
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="tsb-14 block relative w-full min-h-svh bg-tsb14-bg text-tsb14-ink font-tsb14-sans leading-[1.55]" aria-label="Meridian admin">
<div class="absolute top-3.5 right-3.5 z-60">
<input class="tsb-14-theme-input peer absolute inset-0 w-full h-full m-0 opacity-0 cursor-pointer" type="checkbox" id="tsb-14-theme">
<label class="grid place-items-center w-11 h-11 rounded-[0.35rem] border border-tsb14-line bg-tsb14-surf text-tsb14-ink cursor-pointer peer-focus-visible:outline-2 peer-focus-visible:outline-tsb14-acc peer-focus-visible:outline-offset-2" for="tsb-14-theme">
<svg class="w-4.5 h-4.5" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="8.5" fill="none" stroke="currentColor" stroke-width="1.6"/><path d="M12 3.5a8.5 8.5 0 0 0 0 17Z" fill="currentColor"/></svg>
<span class="absolute w-px h-px overflow-hidden whitespace-nowrap [clip-path:inset(50%)]">Toggle dark theme</span>
</label>
</div>
<div class="grid grid-cols-[minmax(0,1fr)] min-h-svh bg-tsb14-surf r46:grid-cols-[minmax(0,15rem)_minmax(0,1fr)]">
<nav class="min-w-0 px-2 pt-4 pb-5 bg-tsb14-surf2 border-b border-tsb14-line r46:border-b-0 r46:border-r r46:border-tsb14-line" aria-label="Meridian admin">
<p class="m-0 mb-3 px-2.5 font-tsb14-display text-[1.15rem]">Meridian</p>
<ul class="list-none m-0 p-0">
<li><a class="relative flex items-center gap-2 min-w-0 min-h-11 px-2.5 py-2 rounded-[0.3rem] text-[0.91rem] text-tsb14-ink no-underline hover:bg-tsb14-surf3 focus-visible:outline-2 focus-visible:outline-tsb14-acc focus-visible:-outline-offset-2" href="#tsb-14-main"><span class="flex-none text-[0.7rem] text-tsb14-mut" aria-hidden="true">□</span>Overview</a></li>
</ul>
<details class="group my-0.5" open>
<summary class="flex items-center gap-2 min-h-11 px-2.5 py-2 rounded-[0.3rem] text-[0.91rem] font-semibold cursor-pointer list-none [&::-webkit-details-marker]:hidden hover:bg-tsb14-surf3 focus-visible:outline-2 focus-visible:outline-tsb14-acc focus-visible:-outline-offset-2">
<span class="flex-none text-[0.7rem] text-tsb14-mut -rotate-90 transition-transform duration-150 ease-out group-open:rotate-0 motion-reduce:transition-none" aria-hidden="true">▼</span>Infrastructure
<span class="hidden group-has-[a[aria-current=page]]:block absolute w-px h-px overflow-hidden whitespace-nowrap [clip-path:inset(50%)]">contains the current page</span>
<span class="hidden group-has-[a[aria-current=page]]:block flex-none ml-auto w-1.5 h-1.5 rounded-full bg-tsb14-acc" aria-hidden="true"></span>
</summary>
<ul class="list-none m-0 p-0">
<li><a class="relative flex items-center min-w-0 min-h-11 py-2 pr-2.5 pl-7.5 rounded-[0.3rem] text-[0.88rem] text-tsb14-mut no-underline hover:bg-tsb14-surf3 focus-visible:outline-2 focus-visible:outline-tsb14-acc focus-visible:-outline-offset-2 aria-[current=page]:bg-tsb14-accsoft aria-[current=page]:text-tsb14-acc aria-[current=page]:font-semibold aria-[current=page]:shadow-[inset_3px_0_0_var(--color-tsb14-acc)]" href="#tsb-14-main">Regions</a></li>
<li><a class="relative flex items-center min-w-0 min-h-11 py-2 pr-2.5 pl-7.5 rounded-[0.3rem] text-[0.88rem] text-tsb14-mut no-underline hover:bg-tsb14-surf3 focus-visible:outline-2 focus-visible:outline-tsb14-acc focus-visible:-outline-offset-2 aria-[current=page]:bg-tsb14-accsoft aria-[current=page]:text-tsb14-acc aria-[current=page]:font-semibold aria-[current=page]:shadow-[inset_3px_0_0_var(--color-tsb14-acc)]" href="#tsb-14-main" aria-current="page">Deployments</a></li>
<li><a class="relative flex items-center min-w-0 min-h-11 py-2 pr-2.5 pl-7.5 rounded-[0.3rem] text-[0.88rem] text-tsb14-mut no-underline hover:bg-tsb14-surf3 focus-visible:outline-2 focus-visible:outline-tsb14-acc focus-visible:-outline-offset-2 aria-[current=page]:bg-tsb14-accsoft aria-[current=page]:text-tsb14-acc aria-[current=page]:font-semibold aria-[current=page]:shadow-[inset_3px_0_0_var(--color-tsb14-acc)]" href="#tsb-14-main">Certificates</a></li>
</ul>
</details>
<details class="group my-0.5">
<summary class="flex items-center gap-2 min-h-11 px-2.5 py-2 rounded-[0.3rem] text-[0.91rem] font-semibold cursor-pointer list-none [&::-webkit-details-marker]:hidden hover:bg-tsb14-surf3 focus-visible:outline-2 focus-visible:outline-tsb14-acc focus-visible:-outline-offset-2">
<span class="flex-none text-[0.7rem] text-tsb14-mut -rotate-90 transition-transform duration-150 ease-out group-open:rotate-0 motion-reduce:transition-none" aria-hidden="true">▼</span>Access
<span class="hidden group-has-[a[aria-current=page]]:block absolute w-px h-px overflow-hidden whitespace-nowrap [clip-path:inset(50%)]">contains the current page</span>
<span class="hidden group-has-[a[aria-current=page]]:block flex-none ml-auto w-1.5 h-1.5 rounded-full bg-tsb14-acc" aria-hidden="true"></span>
</summary>
<ul class="list-none m-0 p-0">
<li><a class="relative flex items-center min-w-0 min-h-11 py-2 pr-2.5 pl-7.5 rounded-[0.3rem] text-[0.88rem] text-tsb14-mut no-underline hover:bg-tsb14-surf3 focus-visible:outline-2 focus-visible:outline-tsb14-acc focus-visible:-outline-offset-2" href="#tsb-14-main">Members</a></li>
<li><a class="relative flex items-center min-w-0 min-h-11 py-2 pr-2.5 pl-7.5 rounded-[0.3rem] text-[0.88rem] text-tsb14-mut no-underline hover:bg-tsb14-surf3 focus-visible:outline-2 focus-visible:outline-tsb14-acc focus-visible:-outline-offset-2" href="#tsb-14-main">API keys</a></li>
<li><a class="relative flex items-center min-w-0 min-h-11 py-2 pr-2.5 pl-7.5 rounded-[0.3rem] text-[0.88rem] text-tsb14-mut no-underline hover:bg-tsb14-surf3 focus-visible:outline-2 focus-visible:outline-tsb14-acc focus-visible:-outline-offset-2" href="#tsb-14-main">Audit log</a></li>
</ul>
</details>
<ul class="list-none m-0 p-0">
<li><a class="relative flex items-center gap-2 min-w-0 min-h-11 px-2.5 py-2 rounded-[0.3rem] text-[0.91rem] text-tsb14-ink no-underline hover:bg-tsb14-surf3 focus-visible:outline-2 focus-visible:outline-tsb14-acc focus-visible:-outline-offset-2" href="#tsb-14-main"><span class="flex-none text-[0.7rem] text-tsb14-mut" aria-hidden="true">□</span>Billing</a></li>
</ul>
</nav>
<main class="min-w-0 content-start px-5 pt-6 pb-10 r46:px-9 r46:pt-10 r46:pb-12" id="tsb-14-main">
<p class="m-0 mb-1 text-[0.82rem] text-tsb14-mut">Infrastructure → <span class="font-semibold text-tsb14-acc">Deployments</span></p>
<h2 class="m-0 mb-5 font-tsb14-display text-[clamp(1.45rem,3.6vw,2.1rem)] leading-[1.1]">Deployments</h2>
<ul class="list-none m-0 p-0 grid gap-px max-w-[48rem] bg-tsb14-line border border-tsb14-line [&>li]:flex [&>li]:flex-wrap [&>li]:items-baseline [&>li]:gap-2.5 [&>li]:min-w-0 [&>li]:px-3.5 [&>li]:py-2.5 [&>li]:bg-tsb14-surf [&>li]:text-[0.88rem] [&>li>em]:ml-auto [&>li>em]:not-italic [&>li>em]:text-[0.8rem] [&>li>em]:text-tsb14-mut">
<li><span class="font-tsb14-mono text-[0.82rem] text-tsb14-acc">4c19f2a</span><span>eu-west-1</span><em>Promoted 09:14 · Alex Chen</em></li>
<li><span class="font-tsb14-mono text-[0.82rem] text-tsb14-acc">9ab7d10</span><span>eu-west-1</span><em>Building · Priya Sharma</em></li>
<li><span class="font-tsb14-mono text-[0.82rem] text-tsb14-acc">17c40be</span><span>us-east-1</span><em>Rolled back · Jordan Lee</em></li>
<li><span class="font-tsb14-mono text-[0.82rem] text-tsb14-acc">08e5cc1</span><span>ap-south-1</span><em>Promoted 07:41 · Ada Okafor</em></li>
<li><span class="font-tsb14-mono text-[0.82rem] text-tsb14-acc">b7712fd</span><span>eu-west-1</span><em>Superseded · Sam Rivera</em></li>
</ul>
</main>
</div>
</section><section class="tsb-14 block relative w-full min-h-svh bg-tsb14-bg text-tsb14-ink font-tsb14-sans leading-[1.55]" aria-label="Meridian admin">
<div class="absolute top-3.5 right-3.5 z-60">
<input class="tsb-14-theme-input peer absolute inset-0 w-full h-full m-0 opacity-0 cursor-pointer" type="checkbox" id="tsb-14-theme">
<label class="grid place-items-center w-11 h-11 rounded-[0.35rem] border border-tsb14-line bg-tsb14-surf text-tsb14-ink cursor-pointer peer-focus-visible:outline-2 peer-focus-visible:outline-tsb14-acc peer-focus-visible:outline-offset-2" for="tsb-14-theme">
<svg class="w-4.5 h-4.5" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="8.5" fill="none" stroke="currentColor" stroke-width="1.6"/><path d="M12 3.5a8.5 8.5 0 0 0 0 17Z" fill="currentColor"/></svg>
<span class="absolute w-px h-px overflow-hidden whitespace-nowrap [clip-path:inset(50%)]">Toggle dark theme</span>
</label>
</div>
<div class="grid grid-cols-[minmax(0,1fr)] min-h-svh bg-tsb14-surf r46:grid-cols-[minmax(0,15rem)_minmax(0,1fr)]">
<nav class="min-w-0 px-2 pt-4 pb-5 bg-tsb14-surf2 border-b border-tsb14-line r46:border-b-0 r46:border-r r46:border-tsb14-line" aria-label="Meridian admin">
<p class="m-0 mb-3 px-2.5 font-tsb14-display text-[1.15rem]">Meridian</p>
<ul class="list-none m-0 p-0">
<li><a class="relative flex items-center gap-2 min-w-0 min-h-11 px-2.5 py-2 rounded-[0.3rem] text-[0.91rem] text-tsb14-ink no-underline hover:bg-tsb14-surf3 focus-visible:outline-2 focus-visible:outline-tsb14-acc focus-visible:-outline-offset-2" href="#tsb-14-main"><span class="flex-none text-[0.7rem] text-tsb14-mut" aria-hidden="true">□</span>Overview</a></li>
</ul>
<details class="group my-0.5" open>
<summary class="flex items-center gap-2 min-h-11 px-2.5 py-2 rounded-[0.3rem] text-[0.91rem] font-semibold cursor-pointer list-none [&::-webkit-details-marker]:hidden hover:bg-tsb14-surf3 focus-visible:outline-2 focus-visible:outline-tsb14-acc focus-visible:-outline-offset-2">
<span class="flex-none text-[0.7rem] text-tsb14-mut -rotate-90 transition-transform duration-150 ease-out group-open:rotate-0 motion-reduce:transition-none" aria-hidden="true">▼</span>Infrastructure
<span class="hidden group-has-[a[aria-current=page]]:block absolute w-px h-px overflow-hidden whitespace-nowrap [clip-path:inset(50%)]">contains the current page</span>
<span class="hidden group-has-[a[aria-current=page]]:block flex-none ml-auto w-1.5 h-1.5 rounded-full bg-tsb14-acc" aria-hidden="true"></span>
</summary>
<ul class="list-none m-0 p-0">
<li><a class="relative flex items-center min-w-0 min-h-11 py-2 pr-2.5 pl-7.5 rounded-[0.3rem] text-[0.88rem] text-tsb14-mut no-underline hover:bg-tsb14-surf3 focus-visible:outline-2 focus-visible:outline-tsb14-acc focus-visible:-outline-offset-2 aria-[current=page]:bg-tsb14-accsoft aria-[current=page]:text-tsb14-acc aria-[current=page]:font-semibold aria-[current=page]:shadow-[inset_3px_0_0_var(--color-tsb14-acc)]" href="#tsb-14-main">Regions</a></li>
<li><a class="relative flex items-center min-w-0 min-h-11 py-2 pr-2.5 pl-7.5 rounded-[0.3rem] text-[0.88rem] text-tsb14-mut no-underline hover:bg-tsb14-surf3 focus-visible:outline-2 focus-visible:outline-tsb14-acc focus-visible:-outline-offset-2 aria-[current=page]:bg-tsb14-accsoft aria-[current=page]:text-tsb14-acc aria-[current=page]:font-semibold aria-[current=page]:shadow-[inset_3px_0_0_var(--color-tsb14-acc)]" href="#tsb-14-main" aria-current="page">Deployments</a></li>
<li><a class="relative flex items-center min-w-0 min-h-11 py-2 pr-2.5 pl-7.5 rounded-[0.3rem] text-[0.88rem] text-tsb14-mut no-underline hover:bg-tsb14-surf3 focus-visible:outline-2 focus-visible:outline-tsb14-acc focus-visible:-outline-offset-2 aria-[current=page]:bg-tsb14-accsoft aria-[current=page]:text-tsb14-acc aria-[current=page]:font-semibold aria-[current=page]:shadow-[inset_3px_0_0_var(--color-tsb14-acc)]" href="#tsb-14-main">Certificates</a></li>
</ul>
</details>
<details class="group my-0.5">
<summary class="flex items-center gap-2 min-h-11 px-2.5 py-2 rounded-[0.3rem] text-[0.91rem] font-semibold cursor-pointer list-none [&::-webkit-details-marker]:hidden hover:bg-tsb14-surf3 focus-visible:outline-2 focus-visible:outline-tsb14-acc focus-visible:-outline-offset-2">
<span class="flex-none text-[0.7rem] text-tsb14-mut -rotate-90 transition-transform duration-150 ease-out group-open:rotate-0 motion-reduce:transition-none" aria-hidden="true">▼</span>Access
<span class="hidden group-has-[a[aria-current=page]]:block absolute w-px h-px overflow-hidden whitespace-nowrap [clip-path:inset(50%)]">contains the current page</span>
<span class="hidden group-has-[a[aria-current=page]]:block flex-none ml-auto w-1.5 h-1.5 rounded-full bg-tsb14-acc" aria-hidden="true"></span>
</summary>
<ul class="list-none m-0 p-0">
<li><a class="relative flex items-center min-w-0 min-h-11 py-2 pr-2.5 pl-7.5 rounded-[0.3rem] text-[0.88rem] text-tsb14-mut no-underline hover:bg-tsb14-surf3 focus-visible:outline-2 focus-visible:outline-tsb14-acc focus-visible:-outline-offset-2" href="#tsb-14-main">Members</a></li>
<li><a class="relative flex items-center min-w-0 min-h-11 py-2 pr-2.5 pl-7.5 rounded-[0.3rem] text-[0.88rem] text-tsb14-mut no-underline hover:bg-tsb14-surf3 focus-visible:outline-2 focus-visible:outline-tsb14-acc focus-visible:-outline-offset-2" href="#tsb-14-main">API keys</a></li>
<li><a class="relative flex items-center min-w-0 min-h-11 py-2 pr-2.5 pl-7.5 rounded-[0.3rem] text-[0.88rem] text-tsb14-mut no-underline hover:bg-tsb14-surf3 focus-visible:outline-2 focus-visible:outline-tsb14-acc focus-visible:-outline-offset-2" href="#tsb-14-main">Audit log</a></li>
</ul>
</details>
<ul class="list-none m-0 p-0">
<li><a class="relative flex items-center gap-2 min-w-0 min-h-11 px-2.5 py-2 rounded-[0.3rem] text-[0.91rem] text-tsb14-ink no-underline hover:bg-tsb14-surf3 focus-visible:outline-2 focus-visible:outline-tsb14-acc focus-visible:-outline-offset-2" href="#tsb-14-main"><span class="flex-none text-[0.7rem] text-tsb14-mut" aria-hidden="true">□</span>Billing</a></li>
</ul>
</nav>
<main class="min-w-0 content-start px-5 pt-6 pb-10 r46:px-9 r46:pt-10 r46:pb-12" id="tsb-14-main">
<p class="m-0 mb-1 text-[0.82rem] text-tsb14-mut">Infrastructure → <span class="font-semibold text-tsb14-acc">Deployments</span></p>
<h2 class="m-0 mb-5 font-tsb14-display text-[clamp(1.45rem,3.6vw,2.1rem)] leading-[1.1]">Deployments</h2>
<ul class="list-none m-0 p-0 grid gap-px max-w-[48rem] bg-tsb14-line border border-tsb14-line [&>li]:flex [&>li]:flex-wrap [&>li]:items-baseline [&>li]:gap-2.5 [&>li]:min-w-0 [&>li]:px-3.5 [&>li]:py-2.5 [&>li]:bg-tsb14-surf [&>li]:text-[0.88rem] [&>li>em]:ml-auto [&>li>em]:not-italic [&>li>em]:text-[0.8rem] [&>li>em]:text-tsb14-mut">
<li><span class="font-tsb14-mono text-[0.82rem] text-tsb14-acc">4c19f2a</span><span>eu-west-1</span><em>Promoted 09:14 · Alex Chen</em></li>
<li><span class="font-tsb14-mono text-[0.82rem] text-tsb14-acc">9ab7d10</span><span>eu-west-1</span><em>Building · Priya Sharma</em></li>
<li><span class="font-tsb14-mono text-[0.82rem] text-tsb14-acc">17c40be</span><span>us-east-1</span><em>Rolled back · Jordan Lee</em></li>
<li><span class="font-tsb14-mono text-[0.82rem] text-tsb14-acc">08e5cc1</span><span>ap-south-1</span><em>Promoted 07:41 · Ada Okafor</em></li>
<li><span class="font-tsb14-mono text-[0.82rem] text-tsb14-acc">b7712fd</span><span>eu-west-1</span><em>Superseded · Sam Rivera</em></li>
</ul>
</main>
</div>
</section>@import "tailwindcss";
@theme {
--color-tsb14-bg: #f2f3f2;
--color-tsb14-bg: oklch(95.5% 0.004 160);
--color-tsb14-surf: #fbfbfa;
--color-tsb14-surf: oklch(98.5% 0.003 160);
--color-tsb14-surf2: #e7e9e7;
--color-tsb14-surf2: oklch(92.5% 0.006 160);
--color-tsb14-surf3: #dcdfdc;
--color-tsb14-surf3: oklch(89% 0.008 160);
--color-tsb14-line: #cdd1cd;
--color-tsb14-line: oklch(84.5% 0.008 160);
--color-tsb14-ink: #161a18;
--color-tsb14-ink: oklch(21% 0.008 170);
--color-tsb14-mut: #5c625f;
--color-tsb14-mut: oklch(47% 0.01 170);
--color-tsb14-acc: #0d6b62;
--color-tsb14-acc: oklch(46% 0.09 190);
--color-tsb14-accsoft: #d5e8e5;
--color-tsb14-accsoft: oklch(91% 0.025 190);
--font-tsb14-sans: system-ui, -apple-system, 'Segoe UI', sans-serif;
--font-tsb14-display: 'Lora', 'Iowan Old Style', Palatino, Georgia, serif;
--font-tsb14-mono: 'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
--breakpoint-r46: 46rem;
}
/* Root rule: the full-bleed contract, stated in CSS as well as in the markup's
w-full min-h-svh. */
.tsb-14 {
width: 100%;
min-height: 100svh;
}
.tsb-14 *,
.tsb-14 *::before,
.tsb-14 *::after {
box-sizing: border-box;
}
/* Token flip for the pure-CSS theme toggle, plus the two mandatory mirror blocks. */
.tsb-14:has(.tsb-14-theme-input:checked) {
--color-tsb14-bg: #0c100e;
--color-tsb14-surf: #141917;
--color-tsb14-surf2: #1b211f;
--color-tsb14-surf3: #232b28;
--color-tsb14-line: #2b3532;
--color-tsb14-ink: #e9efec;
--color-tsb14-mut: #94a09c;
--color-tsb14-acc: #6fd2c6;
--color-tsb14-acc: oklch(82% 0.1 190);
--color-tsb14-accsoft: #14302c;
}
@media (prefers-color-scheme: dark) {
.tsb-14 {
--color-tsb14-bg: #0c100e;
--color-tsb14-surf: #141917;
--color-tsb14-surf2: #1b211f;
--color-tsb14-surf3: #232b28;
--color-tsb14-line: #2b3532;
--color-tsb14-ink: #e9efec;
--color-tsb14-mut: #94a09c;
--color-tsb14-acc: #6fd2c6;
--color-tsb14-acc: oklch(82% 0.1 190);
--color-tsb14-accsoft: #14302c;
}
.tsb-14:has(.tsb-14-theme-input:checked) {
--color-tsb14-bg: #f2f3f2;
--color-tsb14-surf: #fbfbfa;
--color-tsb14-surf2: #e7e9e7;
--color-tsb14-surf3: #dcdfdc;
--color-tsb14-line: #cdd1cd;
--color-tsb14-ink: #161a18;
--color-tsb14-mut: #5c625f;
--color-tsb14-acc: #0d6b62;
--color-tsb14-acc: oklch(46% 0.09 190);
--color-tsb14-accsoft: #d5e8e5;
}
}
@media (prefers-color-scheme: light) {
.tsb-14:has(.tsb-14-theme-input:checked) {
--color-tsb14-bg: #0c100e;
--color-tsb14-surf: #141917;
--color-tsb14-surf2: #1b211f;
--color-tsb14-surf3: #232b28;
--color-tsb14-line: #2b3532;
--color-tsb14-ink: #e9efec;
--color-tsb14-mut: #94a09c;
--color-tsb14-acc: #6fd2c6;
--color-tsb14-acc: oklch(82% 0.1 190);
--color-tsb14-accsoft: #14302c;
}
}@import "tailwindcss";
@theme {
--color-tsb14-bg: #f2f3f2;
--color-tsb14-bg: oklch(95.5% 0.004 160);
--color-tsb14-surf: #fbfbfa;
--color-tsb14-surf: oklch(98.5% 0.003 160);
--color-tsb14-surf2: #e7e9e7;
--color-tsb14-surf2: oklch(92.5% 0.006 160);
--color-tsb14-surf3: #dcdfdc;
--color-tsb14-surf3: oklch(89% 0.008 160);
--color-tsb14-line: #cdd1cd;
--color-tsb14-line: oklch(84.5% 0.008 160);
--color-tsb14-ink: #161a18;
--color-tsb14-ink: oklch(21% 0.008 170);
--color-tsb14-mut: #5c625f;
--color-tsb14-mut: oklch(47% 0.01 170);
--color-tsb14-acc: #0d6b62;
--color-tsb14-acc: oklch(46% 0.09 190);
--color-tsb14-accsoft: #d5e8e5;
--color-tsb14-accsoft: oklch(91% 0.025 190);
--font-tsb14-sans: system-ui, -apple-system, 'Segoe UI', sans-serif;
--font-tsb14-display: 'Lora', 'Iowan Old Style', Palatino, Georgia, serif;
--font-tsb14-mono: 'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
--breakpoint-r46: 46rem;
}
/* Root rule: the full-bleed contract, stated in CSS as well as in the markup's
w-full min-h-svh. */
.tsb-14 {
width: 100%;
min-height: 100svh;
}
.tsb-14 *,
.tsb-14 *::before,
.tsb-14 *::after {
box-sizing: border-box;
}
/* Token flip for the pure-CSS theme toggle, plus the two mandatory mirror blocks. */
.tsb-14:has(.tsb-14-theme-input:checked) {
--color-tsb14-bg: #0c100e;
--color-tsb14-surf: #141917;
--color-tsb14-surf2: #1b211f;
--color-tsb14-surf3: #232b28;
--color-tsb14-line: #2b3532;
--color-tsb14-ink: #e9efec;
--color-tsb14-mut: #94a09c;
--color-tsb14-acc: #6fd2c6;
--color-tsb14-acc: oklch(82% 0.1 190);
--color-tsb14-accsoft: #14302c;
}
@media (prefers-color-scheme: dark) {
.tsb-14 {
--color-tsb14-bg: #0c100e;
--color-tsb14-surf: #141917;
--color-tsb14-surf2: #1b211f;
--color-tsb14-surf3: #232b28;
--color-tsb14-line: #2b3532;
--color-tsb14-ink: #e9efec;
--color-tsb14-mut: #94a09c;
--color-tsb14-acc: #6fd2c6;
--color-tsb14-acc: oklch(82% 0.1 190);
--color-tsb14-accsoft: #14302c;
}
.tsb-14:has(.tsb-14-theme-input:checked) {
--color-tsb14-bg: #f2f3f2;
--color-tsb14-surf: #fbfbfa;
--color-tsb14-surf2: #e7e9e7;
--color-tsb14-surf3: #dcdfdc;
--color-tsb14-line: #cdd1cd;
--color-tsb14-ink: #161a18;
--color-tsb14-mut: #5c625f;
--color-tsb14-acc: #0d6b62;
--color-tsb14-acc: oklch(46% 0.09 190);
--color-tsb14-accsoft: #d5e8e5;
}
}
@media (prefers-color-scheme: light) {
.tsb-14:has(.tsb-14-theme-input:checked) {
--color-tsb14-bg: #0c100e;
--color-tsb14-surf: #141917;
--color-tsb14-surf2: #1b211f;
--color-tsb14-surf3: #232b28;
--color-tsb14-line: #2b3532;
--color-tsb14-ink: #e9efec;
--color-tsb14-mut: #94a09c;
--color-tsb14-acc: #6fd2c6;
--color-tsb14-acc: oklch(82% 0.1 190);
--color-tsb14-accsoft: #14302c;
}
}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-tsb14-bg: #f2f3f2;
--color-tsb14-bg: oklch(95.5% 0.004 160);
--color-tsb14-surf: #fbfbfa;
--color-tsb14-surf: oklch(98.5% 0.003 160);
--color-tsb14-surf2: #e7e9e7;
--color-tsb14-surf2: oklch(92.5% 0.006 160);
--color-tsb14-surf3: #dcdfdc;
--color-tsb14-surf3: oklch(89% 0.008 160);
--color-tsb14-line: #cdd1cd;
--color-tsb14-line: oklch(84.5% 0.008 160);
--color-tsb14-ink: #161a18;
--color-tsb14-ink: oklch(21% 0.008 170);
--color-tsb14-mut: #5c625f;
--color-tsb14-mut: oklch(47% 0.01 170);
--color-tsb14-acc: #0d6b62;
--color-tsb14-acc: oklch(46% 0.09 190);
--color-tsb14-accsoft: #d5e8e5;
--color-tsb14-accsoft: oklch(91% 0.025 190);
--font-tsb14-sans: system-ui, -apple-system, 'Segoe UI', sans-serif;
--font-tsb14-display: 'Lora', 'Iowan Old Style', Palatino, Georgia, serif;
--font-tsb14-mono: 'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
--breakpoint-r46: 46rem;
}
/* Root rule: the full-bleed contract, stated in CSS as well as in the markup's
w-full min-h-svh. */
.tsb-14 {
width: 100%;
min-height: 100svh;
}
.tsb-14 *,
.tsb-14 *::before,
.tsb-14 *::after {
box-sizing: border-box;
}
/* Token flip for the pure-CSS theme toggle, plus the two mandatory mirror blocks. */
.tsb-14:has(.tsb-14-theme-input:checked) {
--color-tsb14-bg: #0c100e;
--color-tsb14-surf: #141917;
--color-tsb14-surf2: #1b211f;
--color-tsb14-surf3: #232b28;
--color-tsb14-line: #2b3532;
--color-tsb14-ink: #e9efec;
--color-tsb14-mut: #94a09c;
--color-tsb14-acc: #6fd2c6;
--color-tsb14-acc: oklch(82% 0.1 190);
--color-tsb14-accsoft: #14302c;
}
@media (prefers-color-scheme: dark) {
.tsb-14 {
--color-tsb14-bg: #0c100e;
--color-tsb14-surf: #141917;
--color-tsb14-surf2: #1b211f;
--color-tsb14-surf3: #232b28;
--color-tsb14-line: #2b3532;
--color-tsb14-ink: #e9efec;
--color-tsb14-mut: #94a09c;
--color-tsb14-acc: #6fd2c6;
--color-tsb14-acc: oklch(82% 0.1 190);
--color-tsb14-accsoft: #14302c;
}
.tsb-14:has(.tsb-14-theme-input:checked) {
--color-tsb14-bg: #f2f3f2;
--color-tsb14-surf: #fbfbfa;
--color-tsb14-surf2: #e7e9e7;
--color-tsb14-surf3: #dcdfdc;
--color-tsb14-line: #cdd1cd;
--color-tsb14-ink: #161a18;
--color-tsb14-mut: #5c625f;
--color-tsb14-acc: #0d6b62;
--color-tsb14-acc: oklch(46% 0.09 190);
--color-tsb14-accsoft: #d5e8e5;
}
}
@media (prefers-color-scheme: light) {
.tsb-14:has(.tsb-14-theme-input:checked) {
--color-tsb14-bg: #0c100e;
--color-tsb14-surf: #141917;
--color-tsb14-surf2: #1b211f;
--color-tsb14-surf3: #232b28;
--color-tsb14-line: #2b3532;
--color-tsb14-ink: #e9efec;
--color-tsb14-mut: #94a09c;
--color-tsb14-acc: #6fd2c6;
--color-tsb14-acc: oklch(82% 0.1 190);
--color-tsb14-accsoft: #14302c;
}
}@import "tailwindcss";
@theme {
--color-tsb14-bg: #f2f3f2;
--color-tsb14-bg: oklch(95.5% 0.004 160);
--color-tsb14-surf: #fbfbfa;
--color-tsb14-surf: oklch(98.5% 0.003 160);
--color-tsb14-surf2: #e7e9e7;
--color-tsb14-surf2: oklch(92.5% 0.006 160);
--color-tsb14-surf3: #dcdfdc;
--color-tsb14-surf3: oklch(89% 0.008 160);
--color-tsb14-line: #cdd1cd;
--color-tsb14-line: oklch(84.5% 0.008 160);
--color-tsb14-ink: #161a18;
--color-tsb14-ink: oklch(21% 0.008 170);
--color-tsb14-mut: #5c625f;
--color-tsb14-mut: oklch(47% 0.01 170);
--color-tsb14-acc: #0d6b62;
--color-tsb14-acc: oklch(46% 0.09 190);
--color-tsb14-accsoft: #d5e8e5;
--color-tsb14-accsoft: oklch(91% 0.025 190);
--font-tsb14-sans: system-ui, -apple-system, 'Segoe UI', sans-serif;
--font-tsb14-display: 'Lora', 'Iowan Old Style', Palatino, Georgia, serif;
--font-tsb14-mono: 'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
--breakpoint-r46: 46rem;
}
/* Root rule: the full-bleed contract, stated in CSS as well as in the markup's
w-full min-h-svh. */
.tsb-14 {
width: 100%;
min-height: 100svh;
}
.tsb-14 *,
.tsb-14 *::before,
.tsb-14 *::after {
box-sizing: border-box;
}
/* Token flip for the pure-CSS theme toggle, plus the two mandatory mirror blocks. */
.tsb-14:has(.tsb-14-theme-input:checked) {
--color-tsb14-bg: #0c100e;
--color-tsb14-surf: #141917;
--color-tsb14-surf2: #1b211f;
--color-tsb14-surf3: #232b28;
--color-tsb14-line: #2b3532;
--color-tsb14-ink: #e9efec;
--color-tsb14-mut: #94a09c;
--color-tsb14-acc: #6fd2c6;
--color-tsb14-acc: oklch(82% 0.1 190);
--color-tsb14-accsoft: #14302c;
}
@media (prefers-color-scheme: dark) {
.tsb-14 {
--color-tsb14-bg: #0c100e;
--color-tsb14-surf: #141917;
--color-tsb14-surf2: #1b211f;
--color-tsb14-surf3: #232b28;
--color-tsb14-line: #2b3532;
--color-tsb14-ink: #e9efec;
--color-tsb14-mut: #94a09c;
--color-tsb14-acc: #6fd2c6;
--color-tsb14-acc: oklch(82% 0.1 190);
--color-tsb14-accsoft: #14302c;
}
.tsb-14:has(.tsb-14-theme-input:checked) {
--color-tsb14-bg: #f2f3f2;
--color-tsb14-surf: #fbfbfa;
--color-tsb14-surf2: #e7e9e7;
--color-tsb14-surf3: #dcdfdc;
--color-tsb14-line: #cdd1cd;
--color-tsb14-ink: #161a18;
--color-tsb14-mut: #5c625f;
--color-tsb14-acc: #0d6b62;
--color-tsb14-acc: oklch(46% 0.09 190);
--color-tsb14-accsoft: #d5e8e5;
}
}
@media (prefers-color-scheme: light) {
.tsb-14:has(.tsb-14-theme-input:checked) {
--color-tsb14-bg: #0c100e;
--color-tsb14-surf: #141917;
--color-tsb14-surf2: #1b211f;
--color-tsb14-surf3: #232b28;
--color-tsb14-line: #2b3532;
--color-tsb14-ink: #e9efec;
--color-tsb14-mut: #94a09c;
--color-tsb14-acc: #6fd2c6;
--color-tsb14-acc: oklch(82% 0.1 190);
--color-tsb14-accsoft: #14302c;
}
}<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=Lora:wght@400;500;600&family=JetBrains+Mono:wght@400;500&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=Lora:wght@400;500;600&family=JetBrains+Mono:wght@400;500&display=swap">What changed in the port
Which parts became utilities, which stayed CSS, and why.
- Every answer to “where am I” is generated from one attribute:
aria-[current=page]:for the item,group-has-[a[aria-current=page]]:for the group badge. There is no active class in the demo at all. - The chevron's closed rotation is the RESTING utility (
-rotate-90) withgroup-open:rotate-0as the override, inverting the CSS version's:not([open])rule. Utility class lists read default-first, so this ordering is easier to scan. - The group marker dot uses the same pattern as demo 09 — a real span plus a visually hidden announcement — deliberately, so the two demos can be diffed against each other.
- Three surface tokens as plain
bg-*utilities do all the depth work; no shadows, so the dark palette needs nothing but token values. - The deployment rows are laid out with parent-level
[&>li]:utilities, which is the honest port of a.rows lirule and keeps five rows from carrying twelve classes each. aria-[current=page]:shadow-[inset_3px_0_0_…]is preferred to a border for the marker because it cannot shift the text when it appears — a detail the CSS version and this one share.
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 Dashboard Sidebar with Current Page State
Source: https://codefronts.com/navigation/tailwind-css-sidebars/tailwind-dashboard-sidebar-with-current-page-state/
Where the user is has to be answered three times in an admin shell — in the rail, in the group that contains the page, and in the breadcrumb — and all three have to agree. This build derives every one of them from aria-current="page" on a single link: the item marker through aria-[current=page]:, the group badge through group-has-[…]:, and the breadcrumb from the same word in the copy.
## HTML
```html
<section class="tsb-14 block relative w-full min-h-svh bg-tsb14-bg text-tsb14-ink font-tsb14-sans leading-[1.55]" aria-label="Meridian admin">
<div class="absolute top-3.5 right-3.5 z-60">
<input class="tsb-14-theme-input peer absolute inset-0 w-full h-full m-0 opacity-0 cursor-pointer" type="checkbox" id="tsb-14-theme">
<label class="grid place-items-center w-11 h-11 rounded-[0.35rem] border border-tsb14-line bg-tsb14-surf text-tsb14-ink cursor-pointer peer-focus-visible:outline-2 peer-focus-visible:outline-tsb14-acc peer-focus-visible:outline-offset-2" for="tsb-14-theme">
<svg class="w-4.5 h-4.5" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="8.5" fill="none" stroke="currentColor" stroke-width="1.6"/><path d="M12 3.5a8.5 8.5 0 0 0 0 17Z" fill="currentColor"/></svg>
<span class="absolute w-px h-px overflow-hidden whitespace-nowrap [clip-path:inset(50%)]">Toggle dark theme</span>
</label>
</div>
<div class="grid grid-cols-[minmax(0,1fr)] min-h-svh bg-tsb14-surf r46:grid-cols-[minmax(0,15rem)_minmax(0,1fr)]">
<nav class="min-w-0 px-2 pt-4 pb-5 bg-tsb14-surf2 border-b border-tsb14-line r46:border-b-0 r46:border-r r46:border-tsb14-line" aria-label="Meridian admin">
<p class="m-0 mb-3 px-2.5 font-tsb14-display text-[1.15rem]">Meridian</p>
<ul class="list-none m-0 p-0">
<li><a class="relative flex items-center gap-2 min-w-0 min-h-11 px-2.5 py-2 rounded-[0.3rem] text-[0.91rem] text-tsb14-ink no-underline hover:bg-tsb14-surf3 focus-visible:outline-2 focus-visible:outline-tsb14-acc focus-visible:-outline-offset-2" href="#tsb-14-main"><span class="flex-none text-[0.7rem] text-tsb14-mut" aria-hidden="true">□</span>Overview</a></li>
</ul>
<details class="group my-0.5" open>
<summary class="flex items-center gap-2 min-h-11 px-2.5 py-2 rounded-[0.3rem] text-[0.91rem] font-semibold cursor-pointer list-none [&::-webkit-details-marker]:hidden hover:bg-tsb14-surf3 focus-visible:outline-2 focus-visible:outline-tsb14-acc focus-visible:-outline-offset-2">
<span class="flex-none text-[0.7rem] text-tsb14-mut -rotate-90 transition-transform duration-150 ease-out group-open:rotate-0 motion-reduce:transition-none" aria-hidden="true">▼</span>Infrastructure
<span class="hidden group-has-[a[aria-current=page]]:block absolute w-px h-px overflow-hidden whitespace-nowrap [clip-path:inset(50%)]">contains the current page</span>
<span class="hidden group-has-[a[aria-current=page]]:block flex-none ml-auto w-1.5 h-1.5 rounded-full bg-tsb14-acc" aria-hidden="true"></span>
</summary>
<ul class="list-none m-0 p-0">
<li><a class="relative flex items-center min-w-0 min-h-11 py-2 pr-2.5 pl-7.5 rounded-[0.3rem] text-[0.88rem] text-tsb14-mut no-underline hover:bg-tsb14-surf3 focus-visible:outline-2 focus-visible:outline-tsb14-acc focus-visible:-outline-offset-2 aria-[current=page]:bg-tsb14-accsoft aria-[current=page]:text-tsb14-acc aria-[current=page]:font-semibold aria-[current=page]:shadow-[inset_3px_0_0_var(--color-tsb14-acc)]" href="#tsb-14-main">Regions</a></li>
<li><a class="relative flex items-center min-w-0 min-h-11 py-2 pr-2.5 pl-7.5 rounded-[0.3rem] text-[0.88rem] text-tsb14-mut no-underline hover:bg-tsb14-surf3 focus-visible:outline-2 focus-visible:outline-tsb14-acc focus-visible:-outline-offset-2 aria-[current=page]:bg-tsb14-accsoft aria-[current=page]:text-tsb14-acc aria-[current=page]:font-semibold aria-[current=page]:shadow-[inset_3px_0_0_var(--color-tsb14-acc)]" href="#tsb-14-main" aria-current="page">Deployments</a></li>
<li><a class="relative flex items-center min-w-0 min-h-11 py-2 pr-2.5 pl-7.5 rounded-[0.3rem] text-[0.88rem] text-tsb14-mut no-underline hover:bg-tsb14-surf3 focus-visible:outline-2 focus-visible:outline-tsb14-acc focus-visible:-outline-offset-2 aria-[current=page]:bg-tsb14-accsoft aria-[current=page]:text-tsb14-acc aria-[current=page]:font-semibold aria-[current=page]:shadow-[inset_3px_0_0_var(--color-tsb14-acc)]" href="#tsb-14-main">Certificates</a></li>
</ul>
</details>
<details class="group my-0.5">
<summary class="flex items-center gap-2 min-h-11 px-2.5 py-2 rounded-[0.3rem] text-[0.91rem] font-semibold cursor-pointer list-none [&::-webkit-details-marker]:hidden hover:bg-tsb14-surf3 focus-visible:outline-2 focus-visible:outline-tsb14-acc focus-visible:-outline-offset-2">
<span class="flex-none text-[0.7rem] text-tsb14-mut -rotate-90 transition-transform duration-150 ease-out group-open:rotate-0 motion-reduce:transition-none" aria-hidden="true">▼</span>Access
<span class="hidden group-has-[a[aria-current=page]]:block absolute w-px h-px overflow-hidden whitespace-nowrap [clip-path:inset(50%)]">contains the current page</span>
<span class="hidden group-has-[a[aria-current=page]]:block flex-none ml-auto w-1.5 h-1.5 rounded-full bg-tsb14-acc" aria-hidden="true"></span>
</summary>
<ul class="list-none m-0 p-0">
<li><a class="relative flex items-center min-w-0 min-h-11 py-2 pr-2.5 pl-7.5 rounded-[0.3rem] text-[0.88rem] text-tsb14-mut no-underline hover:bg-tsb14-surf3 focus-visible:outline-2 focus-visible:outline-tsb14-acc focus-visible:-outline-offset-2" href="#tsb-14-main">Members</a></li>
<li><a class="relative flex items-center min-w-0 min-h-11 py-2 pr-2.5 pl-7.5 rounded-[0.3rem] text-[0.88rem] text-tsb14-mut no-underline hover:bg-tsb14-surf3 focus-visible:outline-2 focus-visible:outline-tsb14-acc focus-visible:-outline-offset-2" href="#tsb-14-main">API keys</a></li>
<li><a class="relative flex items-center min-w-0 min-h-11 py-2 pr-2.5 pl-7.5 rounded-[0.3rem] text-[0.88rem] text-tsb14-mut no-underline hover:bg-tsb14-surf3 focus-visible:outline-2 focus-visible:outline-tsb14-acc focus-visible:-outline-offset-2" href="#tsb-14-main">Audit log</a></li>
</ul>
</details>
<ul class="list-none m-0 p-0">
<li><a class="relative flex items-center gap-2 min-w-0 min-h-11 px-2.5 py-2 rounded-[0.3rem] text-[0.91rem] text-tsb14-ink no-underline hover:bg-tsb14-surf3 focus-visible:outline-2 focus-visible:outline-tsb14-acc focus-visible:-outline-offset-2" href="#tsb-14-main"><span class="flex-none text-[0.7rem] text-tsb14-mut" aria-hidden="true">□</span>Billing</a></li>
</ul>
</nav>
<main class="min-w-0 content-start px-5 pt-6 pb-10 r46:px-9 r46:pt-10 r46:pb-12" id="tsb-14-main">
<p class="m-0 mb-1 text-[0.82rem] text-tsb14-mut">Infrastructure → <span class="font-semibold text-tsb14-acc">Deployments</span></p>
<h2 class="m-0 mb-5 font-tsb14-display text-[clamp(1.45rem,3.6vw,2.1rem)] leading-[1.1]">Deployments</h2>
<ul class="list-none m-0 p-0 grid gap-px max-w-[48rem] bg-tsb14-line border border-tsb14-line [&>li]:flex [&>li]:flex-wrap [&>li]:items-baseline [&>li]:gap-2.5 [&>li]:min-w-0 [&>li]:px-3.5 [&>li]:py-2.5 [&>li]:bg-tsb14-surf [&>li]:text-[0.88rem] [&>li>em]:ml-auto [&>li>em]:not-italic [&>li>em]:text-[0.8rem] [&>li>em]:text-tsb14-mut">
<li><span class="font-tsb14-mono text-[0.82rem] text-tsb14-acc">4c19f2a</span><span>eu-west-1</span><em>Promoted 09:14 · Alex Chen</em></li>
<li><span class="font-tsb14-mono text-[0.82rem] text-tsb14-acc">9ab7d10</span><span>eu-west-1</span><em>Building · Priya Sharma</em></li>
<li><span class="font-tsb14-mono text-[0.82rem] text-tsb14-acc">17c40be</span><span>us-east-1</span><em>Rolled back · Jordan Lee</em></li>
<li><span class="font-tsb14-mono text-[0.82rem] text-tsb14-acc">08e5cc1</span><span>ap-south-1</span><em>Promoted 07:41 · Ada Okafor</em></li>
<li><span class="font-tsb14-mono text-[0.82rem] text-tsb14-acc">b7712fd</span><span>eu-west-1</span><em>Superseded · Sam Rivera</em></li>
</ul>
</main>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tsb14-bg: #f2f3f2;
--color-tsb14-bg: oklch(95.5% 0.004 160);
--color-tsb14-surf: #fbfbfa;
--color-tsb14-surf: oklch(98.5% 0.003 160);
--color-tsb14-surf2: #e7e9e7;
--color-tsb14-surf2: oklch(92.5% 0.006 160);
--color-tsb14-surf3: #dcdfdc;
--color-tsb14-surf3: oklch(89% 0.008 160);
--color-tsb14-line: #cdd1cd;
--color-tsb14-line: oklch(84.5% 0.008 160);
--color-tsb14-ink: #161a18;
--color-tsb14-ink: oklch(21% 0.008 170);
--color-tsb14-mut: #5c625f;
--color-tsb14-mut: oklch(47% 0.01 170);
--color-tsb14-acc: #0d6b62;
--color-tsb14-acc: oklch(46% 0.09 190);
--color-tsb14-accsoft: #d5e8e5;
--color-tsb14-accsoft: oklch(91% 0.025 190);
--font-tsb14-sans: system-ui, -apple-system, 'Segoe UI', sans-serif;
--font-tsb14-display: 'Lora', 'Iowan Old Style', Palatino, Georgia, serif;
--font-tsb14-mono: 'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
--breakpoint-r46: 46rem;
}
/* Root rule: the full-bleed contract, stated in CSS as well as in the markup's
w-full min-h-svh. */
.tsb-14 {
width: 100%;
min-height: 100svh;
}
.tsb-14 *,
.tsb-14 *::before,
.tsb-14 *::after {
box-sizing: border-box;
}
/* Token flip for the pure-CSS theme toggle, plus the two mandatory mirror blocks. */
.tsb-14:has(.tsb-14-theme-input:checked) {
--color-tsb14-bg: #0c100e;
--color-tsb14-surf: #141917;
--color-tsb14-surf2: #1b211f;
--color-tsb14-surf3: #232b28;
--color-tsb14-line: #2b3532;
--color-tsb14-ink: #e9efec;
--color-tsb14-mut: #94a09c;
--color-tsb14-acc: #6fd2c6;
--color-tsb14-acc: oklch(82% 0.1 190);
--color-tsb14-accsoft: #14302c;
}
@media (prefers-color-scheme: dark) {
.tsb-14 {
--color-tsb14-bg: #0c100e;
--color-tsb14-surf: #141917;
--color-tsb14-surf2: #1b211f;
--color-tsb14-surf3: #232b28;
--color-tsb14-line: #2b3532;
--color-tsb14-ink: #e9efec;
--color-tsb14-mut: #94a09c;
--color-tsb14-acc: #6fd2c6;
--color-tsb14-acc: oklch(82% 0.1 190);
--color-tsb14-accsoft: #14302c;
}
.tsb-14:has(.tsb-14-theme-input:checked) {
--color-tsb14-bg: #f2f3f2;
--color-tsb14-surf: #fbfbfa;
--color-tsb14-surf2: #e7e9e7;
--color-tsb14-surf3: #dcdfdc;
--color-tsb14-line: #cdd1cd;
--color-tsb14-ink: #161a18;
--color-tsb14-mut: #5c625f;
--color-tsb14-acc: #0d6b62;
--color-tsb14-acc: oklch(46% 0.09 190);
--color-tsb14-accsoft: #d5e8e5;
}
}
@media (prefers-color-scheme: light) {
.tsb-14:has(.tsb-14-theme-input:checked) {
--color-tsb14-bg: #0c100e;
--color-tsb14-surf: #141917;
--color-tsb14-surf2: #1b211f;
--color-tsb14-surf3: #232b28;
--color-tsb14-line: #2b3532;
--color-tsb14-ink: #e9efec;
--color-tsb14-mut: #94a09c;
--color-tsb14-acc: #6fd2c6;
--color-tsb14-acc: oklch(82% 0.1 190);
--color-tsb14-accsoft: #14302c;
}
}
```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 Dashboard Sidebar with Current Page State
Source: https://codefronts.com/navigation/tailwind-css-sidebars/tailwind-dashboard-sidebar-with-current-page-state/
Where the user is has to be answered three times in an admin shell — in the rail, in the group that contains the page, and in the breadcrumb — and all three have to agree. This build derives every one of them from aria-current="page" on a single link: the item marker through aria-[current=page]:, the group badge through group-has-[…]:, and the breadcrumb from the same word in the copy.
## HTML
```html
<section class="tsb-14 block relative w-full min-h-svh bg-tsb14-bg text-tsb14-ink font-tsb14-sans leading-[1.55]" aria-label="Meridian admin">
<div class="absolute top-3.5 right-3.5 z-60">
<input class="tsb-14-theme-input peer absolute inset-0 w-full h-full m-0 opacity-0 cursor-pointer" type="checkbox" id="tsb-14-theme">
<label class="grid place-items-center w-11 h-11 rounded-[0.35rem] border border-tsb14-line bg-tsb14-surf text-tsb14-ink cursor-pointer peer-focus-visible:outline-2 peer-focus-visible:outline-tsb14-acc peer-focus-visible:outline-offset-2" for="tsb-14-theme">
<svg class="w-4.5 h-4.5" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="8.5" fill="none" stroke="currentColor" stroke-width="1.6"/><path d="M12 3.5a8.5 8.5 0 0 0 0 17Z" fill="currentColor"/></svg>
<span class="absolute w-px h-px overflow-hidden whitespace-nowrap [clip-path:inset(50%)]">Toggle dark theme</span>
</label>
</div>
<div class="grid grid-cols-[minmax(0,1fr)] min-h-svh bg-tsb14-surf r46:grid-cols-[minmax(0,15rem)_minmax(0,1fr)]">
<nav class="min-w-0 px-2 pt-4 pb-5 bg-tsb14-surf2 border-b border-tsb14-line r46:border-b-0 r46:border-r r46:border-tsb14-line" aria-label="Meridian admin">
<p class="m-0 mb-3 px-2.5 font-tsb14-display text-[1.15rem]">Meridian</p>
<ul class="list-none m-0 p-0">
<li><a class="relative flex items-center gap-2 min-w-0 min-h-11 px-2.5 py-2 rounded-[0.3rem] text-[0.91rem] text-tsb14-ink no-underline hover:bg-tsb14-surf3 focus-visible:outline-2 focus-visible:outline-tsb14-acc focus-visible:-outline-offset-2" href="#tsb-14-main"><span class="flex-none text-[0.7rem] text-tsb14-mut" aria-hidden="true">□</span>Overview</a></li>
</ul>
<details class="group my-0.5" open>
<summary class="flex items-center gap-2 min-h-11 px-2.5 py-2 rounded-[0.3rem] text-[0.91rem] font-semibold cursor-pointer list-none [&::-webkit-details-marker]:hidden hover:bg-tsb14-surf3 focus-visible:outline-2 focus-visible:outline-tsb14-acc focus-visible:-outline-offset-2">
<span class="flex-none text-[0.7rem] text-tsb14-mut -rotate-90 transition-transform duration-150 ease-out group-open:rotate-0 motion-reduce:transition-none" aria-hidden="true">▼</span>Infrastructure
<span class="hidden group-has-[a[aria-current=page]]:block absolute w-px h-px overflow-hidden whitespace-nowrap [clip-path:inset(50%)]">contains the current page</span>
<span class="hidden group-has-[a[aria-current=page]]:block flex-none ml-auto w-1.5 h-1.5 rounded-full bg-tsb14-acc" aria-hidden="true"></span>
</summary>
<ul class="list-none m-0 p-0">
<li><a class="relative flex items-center min-w-0 min-h-11 py-2 pr-2.5 pl-7.5 rounded-[0.3rem] text-[0.88rem] text-tsb14-mut no-underline hover:bg-tsb14-surf3 focus-visible:outline-2 focus-visible:outline-tsb14-acc focus-visible:-outline-offset-2 aria-[current=page]:bg-tsb14-accsoft aria-[current=page]:text-tsb14-acc aria-[current=page]:font-semibold aria-[current=page]:shadow-[inset_3px_0_0_var(--color-tsb14-acc)]" href="#tsb-14-main">Regions</a></li>
<li><a class="relative flex items-center min-w-0 min-h-11 py-2 pr-2.5 pl-7.5 rounded-[0.3rem] text-[0.88rem] text-tsb14-mut no-underline hover:bg-tsb14-surf3 focus-visible:outline-2 focus-visible:outline-tsb14-acc focus-visible:-outline-offset-2 aria-[current=page]:bg-tsb14-accsoft aria-[current=page]:text-tsb14-acc aria-[current=page]:font-semibold aria-[current=page]:shadow-[inset_3px_0_0_var(--color-tsb14-acc)]" href="#tsb-14-main" aria-current="page">Deployments</a></li>
<li><a class="relative flex items-center min-w-0 min-h-11 py-2 pr-2.5 pl-7.5 rounded-[0.3rem] text-[0.88rem] text-tsb14-mut no-underline hover:bg-tsb14-surf3 focus-visible:outline-2 focus-visible:outline-tsb14-acc focus-visible:-outline-offset-2 aria-[current=page]:bg-tsb14-accsoft aria-[current=page]:text-tsb14-acc aria-[current=page]:font-semibold aria-[current=page]:shadow-[inset_3px_0_0_var(--color-tsb14-acc)]" href="#tsb-14-main">Certificates</a></li>
</ul>
</details>
<details class="group my-0.5">
<summary class="flex items-center gap-2 min-h-11 px-2.5 py-2 rounded-[0.3rem] text-[0.91rem] font-semibold cursor-pointer list-none [&::-webkit-details-marker]:hidden hover:bg-tsb14-surf3 focus-visible:outline-2 focus-visible:outline-tsb14-acc focus-visible:-outline-offset-2">
<span class="flex-none text-[0.7rem] text-tsb14-mut -rotate-90 transition-transform duration-150 ease-out group-open:rotate-0 motion-reduce:transition-none" aria-hidden="true">▼</span>Access
<span class="hidden group-has-[a[aria-current=page]]:block absolute w-px h-px overflow-hidden whitespace-nowrap [clip-path:inset(50%)]">contains the current page</span>
<span class="hidden group-has-[a[aria-current=page]]:block flex-none ml-auto w-1.5 h-1.5 rounded-full bg-tsb14-acc" aria-hidden="true"></span>
</summary>
<ul class="list-none m-0 p-0">
<li><a class="relative flex items-center min-w-0 min-h-11 py-2 pr-2.5 pl-7.5 rounded-[0.3rem] text-[0.88rem] text-tsb14-mut no-underline hover:bg-tsb14-surf3 focus-visible:outline-2 focus-visible:outline-tsb14-acc focus-visible:-outline-offset-2" href="#tsb-14-main">Members</a></li>
<li><a class="relative flex items-center min-w-0 min-h-11 py-2 pr-2.5 pl-7.5 rounded-[0.3rem] text-[0.88rem] text-tsb14-mut no-underline hover:bg-tsb14-surf3 focus-visible:outline-2 focus-visible:outline-tsb14-acc focus-visible:-outline-offset-2" href="#tsb-14-main">API keys</a></li>
<li><a class="relative flex items-center min-w-0 min-h-11 py-2 pr-2.5 pl-7.5 rounded-[0.3rem] text-[0.88rem] text-tsb14-mut no-underline hover:bg-tsb14-surf3 focus-visible:outline-2 focus-visible:outline-tsb14-acc focus-visible:-outline-offset-2" href="#tsb-14-main">Audit log</a></li>
</ul>
</details>
<ul class="list-none m-0 p-0">
<li><a class="relative flex items-center gap-2 min-w-0 min-h-11 px-2.5 py-2 rounded-[0.3rem] text-[0.91rem] text-tsb14-ink no-underline hover:bg-tsb14-surf3 focus-visible:outline-2 focus-visible:outline-tsb14-acc focus-visible:-outline-offset-2" href="#tsb-14-main"><span class="flex-none text-[0.7rem] text-tsb14-mut" aria-hidden="true">□</span>Billing</a></li>
</ul>
</nav>
<main class="min-w-0 content-start px-5 pt-6 pb-10 r46:px-9 r46:pt-10 r46:pb-12" id="tsb-14-main">
<p class="m-0 mb-1 text-[0.82rem] text-tsb14-mut">Infrastructure → <span class="font-semibold text-tsb14-acc">Deployments</span></p>
<h2 class="m-0 mb-5 font-tsb14-display text-[clamp(1.45rem,3.6vw,2.1rem)] leading-[1.1]">Deployments</h2>
<ul class="list-none m-0 p-0 grid gap-px max-w-[48rem] bg-tsb14-line border border-tsb14-line [&>li]:flex [&>li]:flex-wrap [&>li]:items-baseline [&>li]:gap-2.5 [&>li]:min-w-0 [&>li]:px-3.5 [&>li]:py-2.5 [&>li]:bg-tsb14-surf [&>li]:text-[0.88rem] [&>li>em]:ml-auto [&>li>em]:not-italic [&>li>em]:text-[0.8rem] [&>li>em]:text-tsb14-mut">
<li><span class="font-tsb14-mono text-[0.82rem] text-tsb14-acc">4c19f2a</span><span>eu-west-1</span><em>Promoted 09:14 · Alex Chen</em></li>
<li><span class="font-tsb14-mono text-[0.82rem] text-tsb14-acc">9ab7d10</span><span>eu-west-1</span><em>Building · Priya Sharma</em></li>
<li><span class="font-tsb14-mono text-[0.82rem] text-tsb14-acc">17c40be</span><span>us-east-1</span><em>Rolled back · Jordan Lee</em></li>
<li><span class="font-tsb14-mono text-[0.82rem] text-tsb14-acc">08e5cc1</span><span>ap-south-1</span><em>Promoted 07:41 · Ada Okafor</em></li>
<li><span class="font-tsb14-mono text-[0.82rem] text-tsb14-acc">b7712fd</span><span>eu-west-1</span><em>Superseded · Sam Rivera</em></li>
</ul>
</main>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tsb14-bg: #f2f3f2;
--color-tsb14-bg: oklch(95.5% 0.004 160);
--color-tsb14-surf: #fbfbfa;
--color-tsb14-surf: oklch(98.5% 0.003 160);
--color-tsb14-surf2: #e7e9e7;
--color-tsb14-surf2: oklch(92.5% 0.006 160);
--color-tsb14-surf3: #dcdfdc;
--color-tsb14-surf3: oklch(89% 0.008 160);
--color-tsb14-line: #cdd1cd;
--color-tsb14-line: oklch(84.5% 0.008 160);
--color-tsb14-ink: #161a18;
--color-tsb14-ink: oklch(21% 0.008 170);
--color-tsb14-mut: #5c625f;
--color-tsb14-mut: oklch(47% 0.01 170);
--color-tsb14-acc: #0d6b62;
--color-tsb14-acc: oklch(46% 0.09 190);
--color-tsb14-accsoft: #d5e8e5;
--color-tsb14-accsoft: oklch(91% 0.025 190);
--font-tsb14-sans: system-ui, -apple-system, 'Segoe UI', sans-serif;
--font-tsb14-display: 'Lora', 'Iowan Old Style', Palatino, Georgia, serif;
--font-tsb14-mono: 'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
--breakpoint-r46: 46rem;
}
/* Root rule: the full-bleed contract, stated in CSS as well as in the markup's
w-full min-h-svh. */
.tsb-14 {
width: 100%;
min-height: 100svh;
}
.tsb-14 *,
.tsb-14 *::before,
.tsb-14 *::after {
box-sizing: border-box;
}
/* Token flip for the pure-CSS theme toggle, plus the two mandatory mirror blocks. */
.tsb-14:has(.tsb-14-theme-input:checked) {
--color-tsb14-bg: #0c100e;
--color-tsb14-surf: #141917;
--color-tsb14-surf2: #1b211f;
--color-tsb14-surf3: #232b28;
--color-tsb14-line: #2b3532;
--color-tsb14-ink: #e9efec;
--color-tsb14-mut: #94a09c;
--color-tsb14-acc: #6fd2c6;
--color-tsb14-acc: oklch(82% 0.1 190);
--color-tsb14-accsoft: #14302c;
}
@media (prefers-color-scheme: dark) {
.tsb-14 {
--color-tsb14-bg: #0c100e;
--color-tsb14-surf: #141917;
--color-tsb14-surf2: #1b211f;
--color-tsb14-surf3: #232b28;
--color-tsb14-line: #2b3532;
--color-tsb14-ink: #e9efec;
--color-tsb14-mut: #94a09c;
--color-tsb14-acc: #6fd2c6;
--color-tsb14-acc: oklch(82% 0.1 190);
--color-tsb14-accsoft: #14302c;
}
.tsb-14:has(.tsb-14-theme-input:checked) {
--color-tsb14-bg: #f2f3f2;
--color-tsb14-surf: #fbfbfa;
--color-tsb14-surf2: #e7e9e7;
--color-tsb14-surf3: #dcdfdc;
--color-tsb14-line: #cdd1cd;
--color-tsb14-ink: #161a18;
--color-tsb14-mut: #5c625f;
--color-tsb14-acc: #0d6b62;
--color-tsb14-acc: oklch(46% 0.09 190);
--color-tsb14-accsoft: #d5e8e5;
}
}
@media (prefers-color-scheme: light) {
.tsb-14:has(.tsb-14-theme-input:checked) {
--color-tsb14-bg: #0c100e;
--color-tsb14-surf: #141917;
--color-tsb14-surf2: #1b211f;
--color-tsb14-surf3: #232b28;
--color-tsb14-line: #2b3532;
--color-tsb14-ink: #e9efec;
--color-tsb14-mut: #94a09c;
--color-tsb14-acc: #6fd2c6;
--color-tsb14-acc: oklch(82% 0.1 190);
--color-tsb14-accsoft: #14302c;
}
}
```How this works
One attribute, three answers. The active link carries aria-current="page". From it:
<!-- the item -->
aria-[current=page]:bg-tsb14-accsoft aria-[current=page]:text-tsb14-acc
<!-- the group that contains it -->
<details class="group">…
<span class="hidden group-has-[a[aria-current=page]]:block …">and the breadcrumb repeats the page name as copy. Nothing derives from a class, so nothing can be styled-but-unannounced.
The chevron default is inverted on purpose. The CSS version writes :not([open]) .ico { rotate(-90deg) }. In utilities the closed rotation is the RESTING style and group-open:rotate-0 is the override — fewer negations, and the default state reads first, which is how utility class lists are scanned.
Layered surfaces without shadows. Three flat tones carry the depth: page, rail, hover. It keeps the admin shell quiet and means dark mode needs no shadow retuning — only tokens flip.
Two levels, no script. Native <details> plus :has() covers the whole state machine, as in demo 09.
Make it yours
- Move the active marker to the right edge by changing the inset shadow's sign:
inset_-3px_0_0. - Ship the group containing the current page with
open— this demo does, and it is the behaviour users expect on load. - Make the groups exclusive with a shared
nameattribute on each<details>. - Retheme through
--color-tsb14-acc,--color-tsb14-accsoftand the three surface tokens. - Swap the serif display face in
--font-tsb14-displayplus the font<link>. - Rail width: the single
r46:grid-cols-[minmax(0,15rem)_minmax(0,1fr)].
Gotchas — read before shipping
- Only ONE element in the document may carry
aria-current="page". Marking the group summary as well as the link double-announces the location. - The breadcrumb and the rail must not be able to disagree. Derive both from the router's current route, never from two hand-maintained lists.
group-has-[a[aria-current=page]]:needs the attribute selector written out; the baregroup-has-aria-current:form tests="true".group-open:matches through nested open ancestors — safe here, unsafe in a deeper tree.- An inset box-shadow marker does not affect layout, which is exactly why it is preferred to a border that shifts text by 3px when it appears.
- Do not put
aria-expandedon a<summary>; the browser exposes the state already.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 111+ | 16.4+ | 128+ | 111+ |
:has() (behind group-has-*) is Baseline 2023; <details> and the ARIA have no meaningful floor. Tailwind v4's own generated sheet is the binding constraint.