16 / 20
All 20 in 20 CSS Sidebar Navigation
- 01Accessible Sidebar Navigation ARIA Reference
- 02Sidebar Focus Trap and Restore on Close
- 03Inert Background Content Behind a Drawer
- 04Sidebar Navigation Is Not a Tab List
- 05Announcing Collapsed and Expanded Sidebar State
- 06Roving Tabindex for Sidebar Keyboard Navigation
- 07Persisting Sidebar Collapse State Across Reloads
- 08Sidebar Scroll Containment with Overscroll Behavior
- 09Nested Submenu Keyboard and Screen Reader Behavior
- 10Resizable Sidebar with a Keyboard Accessible Handle
- 11Collapsible Sidebar with Checkbox State
- 12Responsive Sidebar Breakpoint Behavior
- 13Icon Rail Sidebar with Accessible Labels
- 14Dashboard Sidebar with Current Page State
- 15Multi Level Sidebar Menu Disclosure Pattern
- 16Accordion Sidebar with Details and Summary
- 17Sticky Full Height Sidebar Layout Mechanics
- 18Floating Sidebar Stacking and Overlay Order
- 19Off Canvas Sidebar Drawer with Focus Return
- 20Sidebar Footer Pinning with Scrollable Nav
Accordion Sidebar with Details and Summary
Native <details> and <summary> groups, including the name attribute that makes them behave as an exclusive accordion with no script at all. What you get free: a real disclosure control, keyboard operation, and expanded state exposed by the browser. Where it stops: animation, exclusive behaviour on older engines, and the fact that closing a group as another opens can move the item a user was aiming at.
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="sdb-16" aria-label="Quill mail">
<div class="sdb-16__theme">
<input class="sdb-16__theme-input" type="checkbox" id="sdb-16-theme">
<label class="sdb-16__theme-label" for="sdb-16-theme">
<svg 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="sdb-16__sr">Toggle dark theme</span>
</label>
</div>
<div class="sdb-16__app">
<nav class="sdb-16__rail" aria-label="Quill mailboxes">
<div class="sdb-16__rail-head">
<p class="sdb-16__brand">Quill</p>
<p class="sdb-16__who">Sam Rivera</p>
</div>
<details class="sdb-16__group" name="sdb-16-accordion" open>
<summary class="sdb-16__sum">
<svg class="sdb-16__chev" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M9 6l6 6-6 6" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round"/></svg>
Mail
</summary>
<ul class="sdb-16__list">
<li><a class="sdb-16__link" href="#sdb-16-main" aria-current="page">Inbox <span class="sdb-16__n">12 unread</span></a></li>
<li><a class="sdb-16__link" href="#sdb-16-main">Starred</a></li>
<li><a class="sdb-16__link" href="#sdb-16-main">Sent</a></li>
<li><a class="sdb-16__link" href="#sdb-16-main">Drafts <span class="sdb-16__n">3</span></a></li>
</ul>
</details>
<details class="sdb-16__group" name="sdb-16-accordion">
<summary class="sdb-16__sum">
<svg class="sdb-16__chev" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M9 6l6 6-6 6" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round"/></svg>
Shared inboxes
</summary>
<ul class="sdb-16__list">
<li><a class="sdb-16__link" href="#sdb-16-main">Support <span class="sdb-16__n">41 unread</span></a></li>
<li><a class="sdb-16__link" href="#sdb-16-main">Billing</a></li>
<li><a class="sdb-16__link" href="#sdb-16-main">Security reports</a></li>
</ul>
</details>
<details class="sdb-16__group" name="sdb-16-accordion">
<summary class="sdb-16__sum">
<svg class="sdb-16__chev" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M9 6l6 6-6 6" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round"/></svg>
Settings
</summary>
<ul class="sdb-16__list">
<li><a class="sdb-16__link" href="#sdb-16-main">Filters</a></li>
<li><a class="sdb-16__link" href="#sdb-16-main">Signatures</a></li>
<li><a class="sdb-16__link" href="#sdb-16-main">Forwarding</a></li>
</ul>
</details>
</nav>
<main class="sdb-16__main" id="sdb-16-main">
<h2 class="sdb-16__main-h">Inbox</h2>
<ul class="sdb-16__mail">
<li><p class="sdb-16__from">Priya Sharma</p><p class="sdb-16__subj">Rollback runbook — review before Thursday</p><p class="sdb-16__prev">I have added the verification step we discussed…</p></li>
<li><p class="sdb-16__from">Vale Operations</p><p class="sdb-16__subj">Access request: audit log export</p><p class="sdb-16__prev">Jordan needs read access for the quarter…</p></li>
<li><p class="sdb-16__from">Basalt Hosting</p><p class="sdb-16__subj">Certificate renewal completed</p><p class="sdb-16__prev">No action needed. The new certificate…</p></li>
<li><p class="sdb-16__from">Ada Okafor</p><p class="sdb-16__subj">Region failover drill, Friday 14:00</p><p class="sdb-16__prev">Adding you as the observer for eu-west…</p></li>
<li><p class="sdb-16__from">Fern Studio</p><p class="sdb-16__subj">Invoice 4471 attached</p><p class="sdb-16__prev">Net 30, payable on the usual account…</p></li>
</ul>
</main>
</div>
</section><section class="sdb-16" aria-label="Quill mail">
<div class="sdb-16__theme">
<input class="sdb-16__theme-input" type="checkbox" id="sdb-16-theme">
<label class="sdb-16__theme-label" for="sdb-16-theme">
<svg 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="sdb-16__sr">Toggle dark theme</span>
</label>
</div>
<div class="sdb-16__app">
<nav class="sdb-16__rail" aria-label="Quill mailboxes">
<div class="sdb-16__rail-head">
<p class="sdb-16__brand">Quill</p>
<p class="sdb-16__who">Sam Rivera</p>
</div>
<details class="sdb-16__group" name="sdb-16-accordion" open>
<summary class="sdb-16__sum">
<svg class="sdb-16__chev" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M9 6l6 6-6 6" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round"/></svg>
Mail
</summary>
<ul class="sdb-16__list">
<li><a class="sdb-16__link" href="#sdb-16-main" aria-current="page">Inbox <span class="sdb-16__n">12 unread</span></a></li>
<li><a class="sdb-16__link" href="#sdb-16-main">Starred</a></li>
<li><a class="sdb-16__link" href="#sdb-16-main">Sent</a></li>
<li><a class="sdb-16__link" href="#sdb-16-main">Drafts <span class="sdb-16__n">3</span></a></li>
</ul>
</details>
<details class="sdb-16__group" name="sdb-16-accordion">
<summary class="sdb-16__sum">
<svg class="sdb-16__chev" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M9 6l6 6-6 6" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round"/></svg>
Shared inboxes
</summary>
<ul class="sdb-16__list">
<li><a class="sdb-16__link" href="#sdb-16-main">Support <span class="sdb-16__n">41 unread</span></a></li>
<li><a class="sdb-16__link" href="#sdb-16-main">Billing</a></li>
<li><a class="sdb-16__link" href="#sdb-16-main">Security reports</a></li>
</ul>
</details>
<details class="sdb-16__group" name="sdb-16-accordion">
<summary class="sdb-16__sum">
<svg class="sdb-16__chev" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M9 6l6 6-6 6" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round"/></svg>
Settings
</summary>
<ul class="sdb-16__list">
<li><a class="sdb-16__link" href="#sdb-16-main">Filters</a></li>
<li><a class="sdb-16__link" href="#sdb-16-main">Signatures</a></li>
<li><a class="sdb-16__link" href="#sdb-16-main">Forwarding</a></li>
</ul>
</details>
</nav>
<main class="sdb-16__main" id="sdb-16-main">
<h2 class="sdb-16__main-h">Inbox</h2>
<ul class="sdb-16__mail">
<li><p class="sdb-16__from">Priya Sharma</p><p class="sdb-16__subj">Rollback runbook — review before Thursday</p><p class="sdb-16__prev">I have added the verification step we discussed…</p></li>
<li><p class="sdb-16__from">Vale Operations</p><p class="sdb-16__subj">Access request: audit log export</p><p class="sdb-16__prev">Jordan needs read access for the quarter…</p></li>
<li><p class="sdb-16__from">Basalt Hosting</p><p class="sdb-16__subj">Certificate renewal completed</p><p class="sdb-16__prev">No action needed. The new certificate…</p></li>
<li><p class="sdb-16__from">Ada Okafor</p><p class="sdb-16__subj">Region failover drill, Friday 14:00</p><p class="sdb-16__prev">Adding you as the observer for eu-west…</p></li>
<li><p class="sdb-16__from">Fern Studio</p><p class="sdb-16__subj">Invoice 4471 attached</p><p class="sdb-16__prev">Net 30, payable on the usual account…</p></li>
</ul>
</main>
</div>
</section>.sdb-16 {
--sdb-16-bg: #f1f3f5;
--sdb-16-surf: #ffffff;
--sdb-16-surf2: #e7eaee;
--sdb-16-surf3: #dde1e7;
--sdb-16-line: #cfd5dc;
--sdb-16-ink: #131720;
--sdb-16-mut: #59616e;
--sdb-16-acc: #2b4a8f;
--sdb-16-acc: oklch(42% 0.13 264);
--sdb-16-acc-soft: #e0e7f6;
--sdb-16-font-display: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
width: 100%;
min-height: 100vh;
display: block;
position: relative;
box-sizing: border-box;
background: var(--sdb-16-bg);
color: var(--sdb-16-ink);
font-family: system-ui, -apple-system, "Segoe UI", sans-serif;
line-height: 1.55;
}
.sdb-16 *,
.sdb-16 *::before,
.sdb-16 *::after {
box-sizing: border-box;
}
.sdb-16:has(.sdb-16__theme-input:checked) {
--sdb-16-bg: #0b0e14;
--sdb-16-surf: #12161f;
--sdb-16-surf2: #191e29;
--sdb-16-surf3: #202634;
--sdb-16-line: #262d3b;
--sdb-16-ink: #e8ecf3;
--sdb-16-mut: #909aab;
--sdb-16-acc: #8fabf0;
--sdb-16-acc: oklch(78% 0.11 264);
--sdb-16-acc-soft: #1a2238;
}
@media (prefers-color-scheme: dark) {
.sdb-16 {
--sdb-16-bg: #0b0e14;
--sdb-16-surf: #12161f;
--sdb-16-surf2: #191e29;
--sdb-16-surf3: #202634;
--sdb-16-line: #262d3b;
--sdb-16-ink: #e8ecf3;
--sdb-16-mut: #909aab;
--sdb-16-acc: #8fabf0;
--sdb-16-acc: oklch(78% 0.11 264);
--sdb-16-acc-soft: #1a2238;
}
.sdb-16:has(.sdb-16__theme-input:checked) {
--sdb-16-bg: #f1f3f5;
--sdb-16-surf: #ffffff;
--sdb-16-surf2: #e7eaee;
--sdb-16-surf3: #dde1e7;
--sdb-16-line: #cfd5dc;
--sdb-16-ink: #131720;
--sdb-16-mut: #59616e;
--sdb-16-acc: #2b4a8f;
--sdb-16-acc: oklch(42% 0.13 264);
--sdb-16-acc-soft: #e0e7f6;
}
}
@media (prefers-color-scheme: light) {
.sdb-16:has(.sdb-16__theme-input:checked) {
--sdb-16-bg: #0b0e14;
--sdb-16-surf: #12161f;
--sdb-16-surf2: #191e29;
--sdb-16-surf3: #202634;
--sdb-16-line: #262d3b;
--sdb-16-ink: #e8ecf3;
--sdb-16-mut: #909aab;
--sdb-16-acc: #8fabf0;
--sdb-16-acc: oklch(78% 0.11 264);
--sdb-16-acc-soft: #1a2238;
}
}
.sdb-16__theme {
position: absolute;
inset-block-start: 0.85rem;
inset-inline-end: 0.85rem;
z-index: 60;
}
.sdb-16__theme-input {
position: absolute;
inset: 0;
inline-size: 100%;
block-size: 100%;
margin: 0;
opacity: 0;
cursor: pointer;
}
.sdb-16__theme-label {
display: grid;
place-items: center;
inline-size: 2.75rem;
block-size: 2.75rem;
border-radius: 0.6rem;
border: 1px solid var(--sdb-16-line);
background: var(--sdb-16-surf);
color: var(--sdb-16-ink);
cursor: pointer;
}
.sdb-16__theme-label svg {
inline-size: 1.15rem;
block-size: 1.15rem;
}
.sdb-16__theme-input:focus-visible + .sdb-16__theme-label {
outline: 2px solid var(--sdb-16-acc);
outline-offset: 2px;
}
.sdb-16__sr {
position: absolute;
inline-size: 1px;
block-size: 1px;
overflow: hidden;
clip-path: inset(50%);
white-space: nowrap;
}
.sdb-16__app {
display: grid;
grid-template-columns: minmax(0, 1fr);
min-block-size: 100vh;
background: var(--sdb-16-bg);
}
@media (min-width: 46rem) {
.sdb-16__app {
grid-template-columns: minmax(0, 16.5rem) minmax(0, 1fr);
}
}
.sdb-16__rail {
min-inline-size: 0;
align-content: start;
padding: 0.75rem 0.6rem;
background: var(--sdb-16-surf2);
}
@media (min-width: 46rem) {
.sdb-16__rail {
border-inline-end: 1px solid var(--sdb-16-line);
}
}
.sdb-16__rail-head {
padding: 0.5rem 0.6rem 0.8rem;
}
.sdb-16__brand {
margin: 0;
font-family: var(--sdb-16-font-display);
font-size: 1.2rem;
font-weight: 700;
letter-spacing: -0.02em;
color: var(--sdb-16-acc);
}
.sdb-16__who {
margin: 0;
font-size: 0.78rem;
color: var(--sdb-16-mut);
}
.sdb-16__group {
margin-block-end: 0.3rem;
border-radius: 0.6rem;
background: var(--sdb-16-surf);
overflow: hidden;
}
.sdb-16__sum {
display: flex;
align-items: center;
gap: 0.55rem;
min-block-size: 2.75rem;
padding: 0.5rem 0.7rem;
cursor: pointer;
list-style: none;
font-size: 0.92rem;
font-weight: 600;
}
.sdb-16__sum::-webkit-details-marker {
display: none;
}
.sdb-16__sum:hover {
background: var(--sdb-16-surf3);
}
.sdb-16__sum:focus-visible,
.sdb-16__link:focus-visible {
outline: 2px solid var(--sdb-16-acc);
outline-offset: -2px;
}
.sdb-16__chev {
inline-size: 1rem;
block-size: 1rem;
flex: none;
color: var(--sdb-16-mut);
transition: transform 150ms ease;
}
.sdb-16__group[open] .sdb-16__chev {
transform: rotate(90deg);
}
.sdb-16__group:has([aria-current="page"]) .sdb-16__sum {
color: var(--sdb-16-acc);
}
.sdb-16__list {
list-style: none;
margin: 0;
padding: 0 0.35rem 0.4rem;
}
.sdb-16__link {
display: flex;
align-items: center;
gap: 0.5rem;
min-block-size: 2.75rem;
padding: 0.45rem 0.6rem;
border-radius: 0.45rem;
color: var(--sdb-16-ink);
text-decoration: none;
font-size: 0.89rem;
min-inline-size: 0;
}
.sdb-16__link:hover {
background: var(--sdb-16-surf2);
}
.sdb-16__link[aria-current="page"] {
background: var(--sdb-16-acc-soft);
color: var(--sdb-16-acc);
font-weight: 650;
}
.sdb-16__n {
margin-inline-start: auto;
font-size: 0.74rem;
color: var(--sdb-16-mut);
font-variant-numeric: tabular-nums;
}
.sdb-16__link[aria-current="page"] .sdb-16__n {
color: var(--sdb-16-acc);
}
.sdb-16__main {
min-inline-size: 0;
padding: 1.4rem 1.25rem 2.5rem;
align-content: start;
background: var(--sdb-16-surf);
}
@media (min-width: 46rem) {
.sdb-16__main {
padding: 2.2rem 2rem 3rem;
}
}
.sdb-16__main-h {
margin: 0 0 1rem;
font-size: clamp(1.3rem, 3.2vw, 1.7rem);
letter-spacing: -0.015em;
}
.sdb-16__mail {
list-style: none;
margin: 0;
padding: 0;
display: grid;
gap: 0.55rem;
max-inline-size: 46rem;
}
.sdb-16__mail li {
min-inline-size: 0;
padding: 0.75rem 0.85rem;
border-radius: 0.6rem;
background: var(--sdb-16-surf2);
}
.sdb-16__from {
margin: 0;
font-size: 0.78rem;
color: var(--sdb-16-acc);
font-weight: 650;
}
.sdb-16__subj {
margin: 0.05rem 0;
font-size: 0.94rem;
font-weight: 600;
min-inline-size: 0;
}
.sdb-16__prev {
margin: 0;
font-size: 0.82rem;
color: var(--sdb-16-mut);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
@media (prefers-reduced-motion: reduce) {
.sdb-16__chev {
transition: none;
}
}.sdb-16 {
--sdb-16-bg: #f1f3f5;
--sdb-16-surf: #ffffff;
--sdb-16-surf2: #e7eaee;
--sdb-16-surf3: #dde1e7;
--sdb-16-line: #cfd5dc;
--sdb-16-ink: #131720;
--sdb-16-mut: #59616e;
--sdb-16-acc: #2b4a8f;
--sdb-16-acc: oklch(42% 0.13 264);
--sdb-16-acc-soft: #e0e7f6;
--sdb-16-font-display: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
width: 100%;
min-height: 100vh;
display: block;
position: relative;
box-sizing: border-box;
background: var(--sdb-16-bg);
color: var(--sdb-16-ink);
font-family: system-ui, -apple-system, "Segoe UI", sans-serif;
line-height: 1.55;
}
.sdb-16 *,
.sdb-16 *::before,
.sdb-16 *::after {
box-sizing: border-box;
}
.sdb-16:has(.sdb-16__theme-input:checked) {
--sdb-16-bg: #0b0e14;
--sdb-16-surf: #12161f;
--sdb-16-surf2: #191e29;
--sdb-16-surf3: #202634;
--sdb-16-line: #262d3b;
--sdb-16-ink: #e8ecf3;
--sdb-16-mut: #909aab;
--sdb-16-acc: #8fabf0;
--sdb-16-acc: oklch(78% 0.11 264);
--sdb-16-acc-soft: #1a2238;
}
@media (prefers-color-scheme: dark) {
.sdb-16 {
--sdb-16-bg: #0b0e14;
--sdb-16-surf: #12161f;
--sdb-16-surf2: #191e29;
--sdb-16-surf3: #202634;
--sdb-16-line: #262d3b;
--sdb-16-ink: #e8ecf3;
--sdb-16-mut: #909aab;
--sdb-16-acc: #8fabf0;
--sdb-16-acc: oklch(78% 0.11 264);
--sdb-16-acc-soft: #1a2238;
}
.sdb-16:has(.sdb-16__theme-input:checked) {
--sdb-16-bg: #f1f3f5;
--sdb-16-surf: #ffffff;
--sdb-16-surf2: #e7eaee;
--sdb-16-surf3: #dde1e7;
--sdb-16-line: #cfd5dc;
--sdb-16-ink: #131720;
--sdb-16-mut: #59616e;
--sdb-16-acc: #2b4a8f;
--sdb-16-acc: oklch(42% 0.13 264);
--sdb-16-acc-soft: #e0e7f6;
}
}
@media (prefers-color-scheme: light) {
.sdb-16:has(.sdb-16__theme-input:checked) {
--sdb-16-bg: #0b0e14;
--sdb-16-surf: #12161f;
--sdb-16-surf2: #191e29;
--sdb-16-surf3: #202634;
--sdb-16-line: #262d3b;
--sdb-16-ink: #e8ecf3;
--sdb-16-mut: #909aab;
--sdb-16-acc: #8fabf0;
--sdb-16-acc: oklch(78% 0.11 264);
--sdb-16-acc-soft: #1a2238;
}
}
.sdb-16__theme {
position: absolute;
inset-block-start: 0.85rem;
inset-inline-end: 0.85rem;
z-index: 60;
}
.sdb-16__theme-input {
position: absolute;
inset: 0;
inline-size: 100%;
block-size: 100%;
margin: 0;
opacity: 0;
cursor: pointer;
}
.sdb-16__theme-label {
display: grid;
place-items: center;
inline-size: 2.75rem;
block-size: 2.75rem;
border-radius: 0.6rem;
border: 1px solid var(--sdb-16-line);
background: var(--sdb-16-surf);
color: var(--sdb-16-ink);
cursor: pointer;
}
.sdb-16__theme-label svg {
inline-size: 1.15rem;
block-size: 1.15rem;
}
.sdb-16__theme-input:focus-visible + .sdb-16__theme-label {
outline: 2px solid var(--sdb-16-acc);
outline-offset: 2px;
}
.sdb-16__sr {
position: absolute;
inline-size: 1px;
block-size: 1px;
overflow: hidden;
clip-path: inset(50%);
white-space: nowrap;
}
.sdb-16__app {
display: grid;
grid-template-columns: minmax(0, 1fr);
min-block-size: 100vh;
background: var(--sdb-16-bg);
}
@media (min-width: 46rem) {
.sdb-16__app {
grid-template-columns: minmax(0, 16.5rem) minmax(0, 1fr);
}
}
.sdb-16__rail {
min-inline-size: 0;
align-content: start;
padding: 0.75rem 0.6rem;
background: var(--sdb-16-surf2);
}
@media (min-width: 46rem) {
.sdb-16__rail {
border-inline-end: 1px solid var(--sdb-16-line);
}
}
.sdb-16__rail-head {
padding: 0.5rem 0.6rem 0.8rem;
}
.sdb-16__brand {
margin: 0;
font-family: var(--sdb-16-font-display);
font-size: 1.2rem;
font-weight: 700;
letter-spacing: -0.02em;
color: var(--sdb-16-acc);
}
.sdb-16__who {
margin: 0;
font-size: 0.78rem;
color: var(--sdb-16-mut);
}
.sdb-16__group {
margin-block-end: 0.3rem;
border-radius: 0.6rem;
background: var(--sdb-16-surf);
overflow: hidden;
}
.sdb-16__sum {
display: flex;
align-items: center;
gap: 0.55rem;
min-block-size: 2.75rem;
padding: 0.5rem 0.7rem;
cursor: pointer;
list-style: none;
font-size: 0.92rem;
font-weight: 600;
}
.sdb-16__sum::-webkit-details-marker {
display: none;
}
.sdb-16__sum:hover {
background: var(--sdb-16-surf3);
}
.sdb-16__sum:focus-visible,
.sdb-16__link:focus-visible {
outline: 2px solid var(--sdb-16-acc);
outline-offset: -2px;
}
.sdb-16__chev {
inline-size: 1rem;
block-size: 1rem;
flex: none;
color: var(--sdb-16-mut);
transition: transform 150ms ease;
}
.sdb-16__group[open] .sdb-16__chev {
transform: rotate(90deg);
}
.sdb-16__group:has([aria-current="page"]) .sdb-16__sum {
color: var(--sdb-16-acc);
}
.sdb-16__list {
list-style: none;
margin: 0;
padding: 0 0.35rem 0.4rem;
}
.sdb-16__link {
display: flex;
align-items: center;
gap: 0.5rem;
min-block-size: 2.75rem;
padding: 0.45rem 0.6rem;
border-radius: 0.45rem;
color: var(--sdb-16-ink);
text-decoration: none;
font-size: 0.89rem;
min-inline-size: 0;
}
.sdb-16__link:hover {
background: var(--sdb-16-surf2);
}
.sdb-16__link[aria-current="page"] {
background: var(--sdb-16-acc-soft);
color: var(--sdb-16-acc);
font-weight: 650;
}
.sdb-16__n {
margin-inline-start: auto;
font-size: 0.74rem;
color: var(--sdb-16-mut);
font-variant-numeric: tabular-nums;
}
.sdb-16__link[aria-current="page"] .sdb-16__n {
color: var(--sdb-16-acc);
}
.sdb-16__main {
min-inline-size: 0;
padding: 1.4rem 1.25rem 2.5rem;
align-content: start;
background: var(--sdb-16-surf);
}
@media (min-width: 46rem) {
.sdb-16__main {
padding: 2.2rem 2rem 3rem;
}
}
.sdb-16__main-h {
margin: 0 0 1rem;
font-size: clamp(1.3rem, 3.2vw, 1.7rem);
letter-spacing: -0.015em;
}
.sdb-16__mail {
list-style: none;
margin: 0;
padding: 0;
display: grid;
gap: 0.55rem;
max-inline-size: 46rem;
}
.sdb-16__mail li {
min-inline-size: 0;
padding: 0.75rem 0.85rem;
border-radius: 0.6rem;
background: var(--sdb-16-surf2);
}
.sdb-16__from {
margin: 0;
font-size: 0.78rem;
color: var(--sdb-16-acc);
font-weight: 650;
}
.sdb-16__subj {
margin: 0.05rem 0;
font-size: 0.94rem;
font-weight: 600;
min-inline-size: 0;
}
.sdb-16__prev {
margin: 0;
font-size: 0.82rem;
color: var(--sdb-16-mut);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
@media (prefers-reduced-motion: reduce) {
.sdb-16__chev {
transition: none;
}
}Here's a working CSS Sidebar Navigation 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: Accordion Sidebar with Details and Summary
Source: https://codefronts.com/navigation/css-sidebar-navigation/pure-css-accordion-sidebar-for-admin-dashboards/
Native <details> and <summary> groups, including the name attribute that makes them behave as an exclusive accordion with no script at all. What you get free: a real disclosure control, keyboard operation, and expanded state exposed by the browser. Where it stops: animation, exclusive behaviour on older engines, and the fact that closing a group as another opens can move the item a user was aiming at.
## HTML
```html
<section class="sdb-16" aria-label="Quill mail">
<div class="sdb-16__theme">
<input class="sdb-16__theme-input" type="checkbox" id="sdb-16-theme">
<label class="sdb-16__theme-label" for="sdb-16-theme">
<svg 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="sdb-16__sr">Toggle dark theme</span>
</label>
</div>
<div class="sdb-16__app">
<nav class="sdb-16__rail" aria-label="Quill mailboxes">
<div class="sdb-16__rail-head">
<p class="sdb-16__brand">Quill</p>
<p class="sdb-16__who">Sam Rivera</p>
</div>
<details class="sdb-16__group" name="sdb-16-accordion" open>
<summary class="sdb-16__sum">
<svg class="sdb-16__chev" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M9 6l6 6-6 6" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round"/></svg>
Mail
</summary>
<ul class="sdb-16__list">
<li><a class="sdb-16__link" href="#sdb-16-main" aria-current="page">Inbox <span class="sdb-16__n">12 unread</span></a></li>
<li><a class="sdb-16__link" href="#sdb-16-main">Starred</a></li>
<li><a class="sdb-16__link" href="#sdb-16-main">Sent</a></li>
<li><a class="sdb-16__link" href="#sdb-16-main">Drafts <span class="sdb-16__n">3</span></a></li>
</ul>
</details>
<details class="sdb-16__group" name="sdb-16-accordion">
<summary class="sdb-16__sum">
<svg class="sdb-16__chev" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M9 6l6 6-6 6" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round"/></svg>
Shared inboxes
</summary>
<ul class="sdb-16__list">
<li><a class="sdb-16__link" href="#sdb-16-main">Support <span class="sdb-16__n">41 unread</span></a></li>
<li><a class="sdb-16__link" href="#sdb-16-main">Billing</a></li>
<li><a class="sdb-16__link" href="#sdb-16-main">Security reports</a></li>
</ul>
</details>
<details class="sdb-16__group" name="sdb-16-accordion">
<summary class="sdb-16__sum">
<svg class="sdb-16__chev" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M9 6l6 6-6 6" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round"/></svg>
Settings
</summary>
<ul class="sdb-16__list">
<li><a class="sdb-16__link" href="#sdb-16-main">Filters</a></li>
<li><a class="sdb-16__link" href="#sdb-16-main">Signatures</a></li>
<li><a class="sdb-16__link" href="#sdb-16-main">Forwarding</a></li>
</ul>
</details>
</nav>
<main class="sdb-16__main" id="sdb-16-main">
<h2 class="sdb-16__main-h">Inbox</h2>
<ul class="sdb-16__mail">
<li><p class="sdb-16__from">Priya Sharma</p><p class="sdb-16__subj">Rollback runbook — review before Thursday</p><p class="sdb-16__prev">I have added the verification step we discussed…</p></li>
<li><p class="sdb-16__from">Vale Operations</p><p class="sdb-16__subj">Access request: audit log export</p><p class="sdb-16__prev">Jordan needs read access for the quarter…</p></li>
<li><p class="sdb-16__from">Basalt Hosting</p><p class="sdb-16__subj">Certificate renewal completed</p><p class="sdb-16__prev">No action needed. The new certificate…</p></li>
<li><p class="sdb-16__from">Ada Okafor</p><p class="sdb-16__subj">Region failover drill, Friday 14:00</p><p class="sdb-16__prev">Adding you as the observer for eu-west…</p></li>
<li><p class="sdb-16__from">Fern Studio</p><p class="sdb-16__subj">Invoice 4471 attached</p><p class="sdb-16__prev">Net 30, payable on the usual account…</p></li>
</ul>
</main>
</div>
</section>
```
## CSS
```css
.sdb-16 {
--sdb-16-bg: #f1f3f5;
--sdb-16-surf: #ffffff;
--sdb-16-surf2: #e7eaee;
--sdb-16-surf3: #dde1e7;
--sdb-16-line: #cfd5dc;
--sdb-16-ink: #131720;
--sdb-16-mut: #59616e;
--sdb-16-acc: #2b4a8f;
--sdb-16-acc: oklch(42% 0.13 264);
--sdb-16-acc-soft: #e0e7f6;
--sdb-16-font-display: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
width: 100%;
min-height: 100vh;
display: block;
position: relative;
box-sizing: border-box;
background: var(--sdb-16-bg);
color: var(--sdb-16-ink);
font-family: system-ui, -apple-system, "Segoe UI", sans-serif;
line-height: 1.55;
}
.sdb-16 *,
.sdb-16 *::before,
.sdb-16 *::after {
box-sizing: border-box;
}
.sdb-16:has(.sdb-16__theme-input:checked) {
--sdb-16-bg: #0b0e14;
--sdb-16-surf: #12161f;
--sdb-16-surf2: #191e29;
--sdb-16-surf3: #202634;
--sdb-16-line: #262d3b;
--sdb-16-ink: #e8ecf3;
--sdb-16-mut: #909aab;
--sdb-16-acc: #8fabf0;
--sdb-16-acc: oklch(78% 0.11 264);
--sdb-16-acc-soft: #1a2238;
}
@media (prefers-color-scheme: dark) {
.sdb-16 {
--sdb-16-bg: #0b0e14;
--sdb-16-surf: #12161f;
--sdb-16-surf2: #191e29;
--sdb-16-surf3: #202634;
--sdb-16-line: #262d3b;
--sdb-16-ink: #e8ecf3;
--sdb-16-mut: #909aab;
--sdb-16-acc: #8fabf0;
--sdb-16-acc: oklch(78% 0.11 264);
--sdb-16-acc-soft: #1a2238;
}
.sdb-16:has(.sdb-16__theme-input:checked) {
--sdb-16-bg: #f1f3f5;
--sdb-16-surf: #ffffff;
--sdb-16-surf2: #e7eaee;
--sdb-16-surf3: #dde1e7;
--sdb-16-line: #cfd5dc;
--sdb-16-ink: #131720;
--sdb-16-mut: #59616e;
--sdb-16-acc: #2b4a8f;
--sdb-16-acc: oklch(42% 0.13 264);
--sdb-16-acc-soft: #e0e7f6;
}
}
@media (prefers-color-scheme: light) {
.sdb-16:has(.sdb-16__theme-input:checked) {
--sdb-16-bg: #0b0e14;
--sdb-16-surf: #12161f;
--sdb-16-surf2: #191e29;
--sdb-16-surf3: #202634;
--sdb-16-line: #262d3b;
--sdb-16-ink: #e8ecf3;
--sdb-16-mut: #909aab;
--sdb-16-acc: #8fabf0;
--sdb-16-acc: oklch(78% 0.11 264);
--sdb-16-acc-soft: #1a2238;
}
}
.sdb-16__theme {
position: absolute;
inset-block-start: 0.85rem;
inset-inline-end: 0.85rem;
z-index: 60;
}
.sdb-16__theme-input {
position: absolute;
inset: 0;
inline-size: 100%;
block-size: 100%;
margin: 0;
opacity: 0;
cursor: pointer;
}
.sdb-16__theme-label {
display: grid;
place-items: center;
inline-size: 2.75rem;
block-size: 2.75rem;
border-radius: 0.6rem;
border: 1px solid var(--sdb-16-line);
background: var(--sdb-16-surf);
color: var(--sdb-16-ink);
cursor: pointer;
}
.sdb-16__theme-label svg {
inline-size: 1.15rem;
block-size: 1.15rem;
}
.sdb-16__theme-input:focus-visible + .sdb-16__theme-label {
outline: 2px solid var(--sdb-16-acc);
outline-offset: 2px;
}
.sdb-16__sr {
position: absolute;
inline-size: 1px;
block-size: 1px;
overflow: hidden;
clip-path: inset(50%);
white-space: nowrap;
}
.sdb-16__app {
display: grid;
grid-template-columns: minmax(0, 1fr);
min-block-size: 100vh;
background: var(--sdb-16-bg);
}
@media (min-width: 46rem) {
.sdb-16__app {
grid-template-columns: minmax(0, 16.5rem) minmax(0, 1fr);
}
}
.sdb-16__rail {
min-inline-size: 0;
align-content: start;
padding: 0.75rem 0.6rem;
background: var(--sdb-16-surf2);
}
@media (min-width: 46rem) {
.sdb-16__rail {
border-inline-end: 1px solid var(--sdb-16-line);
}
}
.sdb-16__rail-head {
padding: 0.5rem 0.6rem 0.8rem;
}
.sdb-16__brand {
margin: 0;
font-family: var(--sdb-16-font-display);
font-size: 1.2rem;
font-weight: 700;
letter-spacing: -0.02em;
color: var(--sdb-16-acc);
}
.sdb-16__who {
margin: 0;
font-size: 0.78rem;
color: var(--sdb-16-mut);
}
.sdb-16__group {
margin-block-end: 0.3rem;
border-radius: 0.6rem;
background: var(--sdb-16-surf);
overflow: hidden;
}
.sdb-16__sum {
display: flex;
align-items: center;
gap: 0.55rem;
min-block-size: 2.75rem;
padding: 0.5rem 0.7rem;
cursor: pointer;
list-style: none;
font-size: 0.92rem;
font-weight: 600;
}
.sdb-16__sum::-webkit-details-marker {
display: none;
}
.sdb-16__sum:hover {
background: var(--sdb-16-surf3);
}
.sdb-16__sum:focus-visible,
.sdb-16__link:focus-visible {
outline: 2px solid var(--sdb-16-acc);
outline-offset: -2px;
}
.sdb-16__chev {
inline-size: 1rem;
block-size: 1rem;
flex: none;
color: var(--sdb-16-mut);
transition: transform 150ms ease;
}
.sdb-16__group[open] .sdb-16__chev {
transform: rotate(90deg);
}
.sdb-16__group:has([aria-current="page"]) .sdb-16__sum {
color: var(--sdb-16-acc);
}
.sdb-16__list {
list-style: none;
margin: 0;
padding: 0 0.35rem 0.4rem;
}
.sdb-16__link {
display: flex;
align-items: center;
gap: 0.5rem;
min-block-size: 2.75rem;
padding: 0.45rem 0.6rem;
border-radius: 0.45rem;
color: var(--sdb-16-ink);
text-decoration: none;
font-size: 0.89rem;
min-inline-size: 0;
}
.sdb-16__link:hover {
background: var(--sdb-16-surf2);
}
.sdb-16__link[aria-current="page"] {
background: var(--sdb-16-acc-soft);
color: var(--sdb-16-acc);
font-weight: 650;
}
.sdb-16__n {
margin-inline-start: auto;
font-size: 0.74rem;
color: var(--sdb-16-mut);
font-variant-numeric: tabular-nums;
}
.sdb-16__link[aria-current="page"] .sdb-16__n {
color: var(--sdb-16-acc);
}
.sdb-16__main {
min-inline-size: 0;
padding: 1.4rem 1.25rem 2.5rem;
align-content: start;
background: var(--sdb-16-surf);
}
@media (min-width: 46rem) {
.sdb-16__main {
padding: 2.2rem 2rem 3rem;
}
}
.sdb-16__main-h {
margin: 0 0 1rem;
font-size: clamp(1.3rem, 3.2vw, 1.7rem);
letter-spacing: -0.015em;
}
.sdb-16__mail {
list-style: none;
margin: 0;
padding: 0;
display: grid;
gap: 0.55rem;
max-inline-size: 46rem;
}
.sdb-16__mail li {
min-inline-size: 0;
padding: 0.75rem 0.85rem;
border-radius: 0.6rem;
background: var(--sdb-16-surf2);
}
.sdb-16__from {
margin: 0;
font-size: 0.78rem;
color: var(--sdb-16-acc);
font-weight: 650;
}
.sdb-16__subj {
margin: 0.05rem 0;
font-size: 0.94rem;
font-weight: 600;
min-inline-size: 0;
}
.sdb-16__prev {
margin: 0;
font-size: 0.82rem;
color: var(--sdb-16-mut);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
@media (prefers-reduced-motion: reduce) {
.sdb-16__chev {
transition: none;
}
}
```Here's a working CSS Sidebar Navigation 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: Accordion Sidebar with Details and Summary
Source: https://codefronts.com/navigation/css-sidebar-navigation/pure-css-accordion-sidebar-for-admin-dashboards/
Native <details> and <summary> groups, including the name attribute that makes them behave as an exclusive accordion with no script at all. What you get free: a real disclosure control, keyboard operation, and expanded state exposed by the browser. Where it stops: animation, exclusive behaviour on older engines, and the fact that closing a group as another opens can move the item a user was aiming at.
## HTML
```html
<section class="sdb-16" aria-label="Quill mail">
<div class="sdb-16__theme">
<input class="sdb-16__theme-input" type="checkbox" id="sdb-16-theme">
<label class="sdb-16__theme-label" for="sdb-16-theme">
<svg 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="sdb-16__sr">Toggle dark theme</span>
</label>
</div>
<div class="sdb-16__app">
<nav class="sdb-16__rail" aria-label="Quill mailboxes">
<div class="sdb-16__rail-head">
<p class="sdb-16__brand">Quill</p>
<p class="sdb-16__who">Sam Rivera</p>
</div>
<details class="sdb-16__group" name="sdb-16-accordion" open>
<summary class="sdb-16__sum">
<svg class="sdb-16__chev" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M9 6l6 6-6 6" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round"/></svg>
Mail
</summary>
<ul class="sdb-16__list">
<li><a class="sdb-16__link" href="#sdb-16-main" aria-current="page">Inbox <span class="sdb-16__n">12 unread</span></a></li>
<li><a class="sdb-16__link" href="#sdb-16-main">Starred</a></li>
<li><a class="sdb-16__link" href="#sdb-16-main">Sent</a></li>
<li><a class="sdb-16__link" href="#sdb-16-main">Drafts <span class="sdb-16__n">3</span></a></li>
</ul>
</details>
<details class="sdb-16__group" name="sdb-16-accordion">
<summary class="sdb-16__sum">
<svg class="sdb-16__chev" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M9 6l6 6-6 6" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round"/></svg>
Shared inboxes
</summary>
<ul class="sdb-16__list">
<li><a class="sdb-16__link" href="#sdb-16-main">Support <span class="sdb-16__n">41 unread</span></a></li>
<li><a class="sdb-16__link" href="#sdb-16-main">Billing</a></li>
<li><a class="sdb-16__link" href="#sdb-16-main">Security reports</a></li>
</ul>
</details>
<details class="sdb-16__group" name="sdb-16-accordion">
<summary class="sdb-16__sum">
<svg class="sdb-16__chev" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M9 6l6 6-6 6" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round"/></svg>
Settings
</summary>
<ul class="sdb-16__list">
<li><a class="sdb-16__link" href="#sdb-16-main">Filters</a></li>
<li><a class="sdb-16__link" href="#sdb-16-main">Signatures</a></li>
<li><a class="sdb-16__link" href="#sdb-16-main">Forwarding</a></li>
</ul>
</details>
</nav>
<main class="sdb-16__main" id="sdb-16-main">
<h2 class="sdb-16__main-h">Inbox</h2>
<ul class="sdb-16__mail">
<li><p class="sdb-16__from">Priya Sharma</p><p class="sdb-16__subj">Rollback runbook — review before Thursday</p><p class="sdb-16__prev">I have added the verification step we discussed…</p></li>
<li><p class="sdb-16__from">Vale Operations</p><p class="sdb-16__subj">Access request: audit log export</p><p class="sdb-16__prev">Jordan needs read access for the quarter…</p></li>
<li><p class="sdb-16__from">Basalt Hosting</p><p class="sdb-16__subj">Certificate renewal completed</p><p class="sdb-16__prev">No action needed. The new certificate…</p></li>
<li><p class="sdb-16__from">Ada Okafor</p><p class="sdb-16__subj">Region failover drill, Friday 14:00</p><p class="sdb-16__prev">Adding you as the observer for eu-west…</p></li>
<li><p class="sdb-16__from">Fern Studio</p><p class="sdb-16__subj">Invoice 4471 attached</p><p class="sdb-16__prev">Net 30, payable on the usual account…</p></li>
</ul>
</main>
</div>
</section>
```
## CSS
```css
.sdb-16 {
--sdb-16-bg: #f1f3f5;
--sdb-16-surf: #ffffff;
--sdb-16-surf2: #e7eaee;
--sdb-16-surf3: #dde1e7;
--sdb-16-line: #cfd5dc;
--sdb-16-ink: #131720;
--sdb-16-mut: #59616e;
--sdb-16-acc: #2b4a8f;
--sdb-16-acc: oklch(42% 0.13 264);
--sdb-16-acc-soft: #e0e7f6;
--sdb-16-font-display: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
width: 100%;
min-height: 100vh;
display: block;
position: relative;
box-sizing: border-box;
background: var(--sdb-16-bg);
color: var(--sdb-16-ink);
font-family: system-ui, -apple-system, "Segoe UI", sans-serif;
line-height: 1.55;
}
.sdb-16 *,
.sdb-16 *::before,
.sdb-16 *::after {
box-sizing: border-box;
}
.sdb-16:has(.sdb-16__theme-input:checked) {
--sdb-16-bg: #0b0e14;
--sdb-16-surf: #12161f;
--sdb-16-surf2: #191e29;
--sdb-16-surf3: #202634;
--sdb-16-line: #262d3b;
--sdb-16-ink: #e8ecf3;
--sdb-16-mut: #909aab;
--sdb-16-acc: #8fabf0;
--sdb-16-acc: oklch(78% 0.11 264);
--sdb-16-acc-soft: #1a2238;
}
@media (prefers-color-scheme: dark) {
.sdb-16 {
--sdb-16-bg: #0b0e14;
--sdb-16-surf: #12161f;
--sdb-16-surf2: #191e29;
--sdb-16-surf3: #202634;
--sdb-16-line: #262d3b;
--sdb-16-ink: #e8ecf3;
--sdb-16-mut: #909aab;
--sdb-16-acc: #8fabf0;
--sdb-16-acc: oklch(78% 0.11 264);
--sdb-16-acc-soft: #1a2238;
}
.sdb-16:has(.sdb-16__theme-input:checked) {
--sdb-16-bg: #f1f3f5;
--sdb-16-surf: #ffffff;
--sdb-16-surf2: #e7eaee;
--sdb-16-surf3: #dde1e7;
--sdb-16-line: #cfd5dc;
--sdb-16-ink: #131720;
--sdb-16-mut: #59616e;
--sdb-16-acc: #2b4a8f;
--sdb-16-acc: oklch(42% 0.13 264);
--sdb-16-acc-soft: #e0e7f6;
}
}
@media (prefers-color-scheme: light) {
.sdb-16:has(.sdb-16__theme-input:checked) {
--sdb-16-bg: #0b0e14;
--sdb-16-surf: #12161f;
--sdb-16-surf2: #191e29;
--sdb-16-surf3: #202634;
--sdb-16-line: #262d3b;
--sdb-16-ink: #e8ecf3;
--sdb-16-mut: #909aab;
--sdb-16-acc: #8fabf0;
--sdb-16-acc: oklch(78% 0.11 264);
--sdb-16-acc-soft: #1a2238;
}
}
.sdb-16__theme {
position: absolute;
inset-block-start: 0.85rem;
inset-inline-end: 0.85rem;
z-index: 60;
}
.sdb-16__theme-input {
position: absolute;
inset: 0;
inline-size: 100%;
block-size: 100%;
margin: 0;
opacity: 0;
cursor: pointer;
}
.sdb-16__theme-label {
display: grid;
place-items: center;
inline-size: 2.75rem;
block-size: 2.75rem;
border-radius: 0.6rem;
border: 1px solid var(--sdb-16-line);
background: var(--sdb-16-surf);
color: var(--sdb-16-ink);
cursor: pointer;
}
.sdb-16__theme-label svg {
inline-size: 1.15rem;
block-size: 1.15rem;
}
.sdb-16__theme-input:focus-visible + .sdb-16__theme-label {
outline: 2px solid var(--sdb-16-acc);
outline-offset: 2px;
}
.sdb-16__sr {
position: absolute;
inline-size: 1px;
block-size: 1px;
overflow: hidden;
clip-path: inset(50%);
white-space: nowrap;
}
.sdb-16__app {
display: grid;
grid-template-columns: minmax(0, 1fr);
min-block-size: 100vh;
background: var(--sdb-16-bg);
}
@media (min-width: 46rem) {
.sdb-16__app {
grid-template-columns: minmax(0, 16.5rem) minmax(0, 1fr);
}
}
.sdb-16__rail {
min-inline-size: 0;
align-content: start;
padding: 0.75rem 0.6rem;
background: var(--sdb-16-surf2);
}
@media (min-width: 46rem) {
.sdb-16__rail {
border-inline-end: 1px solid var(--sdb-16-line);
}
}
.sdb-16__rail-head {
padding: 0.5rem 0.6rem 0.8rem;
}
.sdb-16__brand {
margin: 0;
font-family: var(--sdb-16-font-display);
font-size: 1.2rem;
font-weight: 700;
letter-spacing: -0.02em;
color: var(--sdb-16-acc);
}
.sdb-16__who {
margin: 0;
font-size: 0.78rem;
color: var(--sdb-16-mut);
}
.sdb-16__group {
margin-block-end: 0.3rem;
border-radius: 0.6rem;
background: var(--sdb-16-surf);
overflow: hidden;
}
.sdb-16__sum {
display: flex;
align-items: center;
gap: 0.55rem;
min-block-size: 2.75rem;
padding: 0.5rem 0.7rem;
cursor: pointer;
list-style: none;
font-size: 0.92rem;
font-weight: 600;
}
.sdb-16__sum::-webkit-details-marker {
display: none;
}
.sdb-16__sum:hover {
background: var(--sdb-16-surf3);
}
.sdb-16__sum:focus-visible,
.sdb-16__link:focus-visible {
outline: 2px solid var(--sdb-16-acc);
outline-offset: -2px;
}
.sdb-16__chev {
inline-size: 1rem;
block-size: 1rem;
flex: none;
color: var(--sdb-16-mut);
transition: transform 150ms ease;
}
.sdb-16__group[open] .sdb-16__chev {
transform: rotate(90deg);
}
.sdb-16__group:has([aria-current="page"]) .sdb-16__sum {
color: var(--sdb-16-acc);
}
.sdb-16__list {
list-style: none;
margin: 0;
padding: 0 0.35rem 0.4rem;
}
.sdb-16__link {
display: flex;
align-items: center;
gap: 0.5rem;
min-block-size: 2.75rem;
padding: 0.45rem 0.6rem;
border-radius: 0.45rem;
color: var(--sdb-16-ink);
text-decoration: none;
font-size: 0.89rem;
min-inline-size: 0;
}
.sdb-16__link:hover {
background: var(--sdb-16-surf2);
}
.sdb-16__link[aria-current="page"] {
background: var(--sdb-16-acc-soft);
color: var(--sdb-16-acc);
font-weight: 650;
}
.sdb-16__n {
margin-inline-start: auto;
font-size: 0.74rem;
color: var(--sdb-16-mut);
font-variant-numeric: tabular-nums;
}
.sdb-16__link[aria-current="page"] .sdb-16__n {
color: var(--sdb-16-acc);
}
.sdb-16__main {
min-inline-size: 0;
padding: 1.4rem 1.25rem 2.5rem;
align-content: start;
background: var(--sdb-16-surf);
}
@media (min-width: 46rem) {
.sdb-16__main {
padding: 2.2rem 2rem 3rem;
}
}
.sdb-16__main-h {
margin: 0 0 1rem;
font-size: clamp(1.3rem, 3.2vw, 1.7rem);
letter-spacing: -0.015em;
}
.sdb-16__mail {
list-style: none;
margin: 0;
padding: 0;
display: grid;
gap: 0.55rem;
max-inline-size: 46rem;
}
.sdb-16__mail li {
min-inline-size: 0;
padding: 0.75rem 0.85rem;
border-radius: 0.6rem;
background: var(--sdb-16-surf2);
}
.sdb-16__from {
margin: 0;
font-size: 0.78rem;
color: var(--sdb-16-acc);
font-weight: 650;
}
.sdb-16__subj {
margin: 0.05rem 0;
font-size: 0.94rem;
font-weight: 600;
min-inline-size: 0;
}
.sdb-16__prev {
margin: 0;
font-size: 0.82rem;
color: var(--sdb-16-mut);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
@media (prefers-reduced-motion: reduce) {
.sdb-16__chev {
transition: none;
}
}
```How this works
<details> gives you the disclosure pattern for free, and it is more than it looks. The <summary> is a real control: focusable, operable with Enter and Space, and exposed to assistive technology with its expanded state already correct. Reproducing that with a <button> means writing aria-expanded, aria-controls, the click handler and the hidden state yourself — four things that can each be wrong.
The name attribute is what turns a stack of disclosures into an accordion. Give several <details> the same name and the browser enforces that only one is open at a time, closing the previous one for you. This landed in Chrome 120, Safari 17.2 and Firefox 130, which is recent enough to need a fallback story — and the fallback is benign: on older engines the groups are simply independent, so more than one can be open. Nothing breaks; the rail just gets taller.
Where native stops is animation and scroll stability. <details> has no built-in open transition; animating it needs interpolate-size or a grid-row trick plus transition-behavior: allow-discrete, and that is a real cost to weigh against writing the button version. The subtler problem is exclusive mode: when one group closes as another opens, everything below moves, so an item the user was about to click shifts out from under the pointer.
The trap is styling the marker. The default triangle is drawn by ::marker in modern engines and by ::-webkit-details-marker in older WebKit, so both need suppressing, and display: flex on the <summary> removes the marker as a side effect in some engines — which is why this demo sets list-style: none explicitly and draws its own chevron.
Make it yours
- Remove the
nameattribute to allow several groups open at once, which suits a rail users keep expanded while working. - Open the group containing the current page on the server so the active item is visible without interaction.
- Animate the open state with
interpolate-size: allow-keywordsand a height transition if you accept the browser floor that comes with it. - Swap the chevron for a plus and minus by targeting
[open]on the group; nothing else changes. - Move the counts out of the link text into a separate element with
aria-hiddenif you do not want them in the accessible name. - Replace
<details>with a scripted button andaria-expandedwhen you need animation and exclusive behaviour on older engines at the same time.
Gotchas — read before shipping
- Exclusive accordions move content: the group above closing shifts everything below, so an item under the pointer moves before the click lands. Consider a scroll anchor, or drop exclusivity.
<details name>is recent — Chrome 120, Safari 17.2, Firefox 130. Older engines ignore it and open groups independently, which is a fine fallback but is not the design you tested.- The default disclosure triangle needs both
list-style: noneand::-webkit-details-markersuppressed, or it survives in one engine and not the other. <details>cannot animate open withoutinterpolate-sizeor a height hack. If the animation is a requirement, the scripted version may be the cheaper route.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 120+ | 17.2+ | 130+ | 120+ |
the <details name> exclusive accordion sets the floor. Engines below it ignore the attribute entirely and treat each group as an independent disclosure — every group still opens, closes and announces correctly, there is just no automatic closing of the previous one. The theme toggle needs :has() (Chrome 105 / Safari 15.4 / Firefox 121), comfortably under this floor.