Bootstrap 5 Responsive Sidebar with Dropdown Menus
A responsive admin sidebar with a profile card, collapsible submenus, badges and a bottom toolbar for notifications, messages, settings and logout. On phones it becomes a slide-in drawer opened from a menu button.
<section class="wdw-stage p-0 align-items-stretch">
<div class="wdw-shell d-flex w-100">
<div class="offcanvas-lg offcanvas-start wdw-side d-flex flex-column" tabindex="-1" id="wdwSide" aria-labelledby="wdwSideTitle">
<div class="d-flex align-items-center justify-content-between px-4 pt-4 pb-3">
<a href="#" class="d-flex align-items-center gap-2 text-decoration-none" id="wdwSideTitle">
<span class="wdw-icon" style="width:2.25rem;height:2.25rem" aria-hidden="true"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M13 2 4 14h7l-1 8 9-12h-7l1-8Z"/></svg></span>
<span class="fw-bold fs-5 text-body-emphasis">Pro Sidebar</span>
</a>
<button type="button" class="btn-close d-lg-none" data-bs-dismiss="offcanvas" data-bs-target="#wdwSide" aria-label="Close menu"></button>
</div>
<div class="mx-3 mb-3 p-3 rounded-4 bg-primary-subtle border border-primary-subtle d-flex align-items-center gap-3">
<img class="rounded-circle" width="44" height="44" src="https://i.pravatar.cc/88?img=32" alt="Profile photo of John Smith">
<div class="lh-sm min-w-0">
<strong class="d-block text-body-emphasis">John Smith</strong>
<small class="wdw-muted d-flex align-items-center gap-1"><span class="wdw-dotlive"></span>Administrator</small>
</div>
</div>
<nav class="px-3 flex-grow-1 overflow-auto" aria-label="Main">
<small class="wdw-eyebrow px-2 mb-2">General</small>
<ul class="list-unstyled d-grid gap-1 mb-0"><li><a class="wdw-nav" href="#"><svg class="wdw-ni" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m3 11 9-8 9 8"/><path d="M5 10v10h14V10"/></svg><span>Overview</span></a></li><li><button class="wdw-nav parent-active" type="button" data-bs-toggle="collapse" data-bs-target="#navShop" aria-expanded="true" aria-controls="navShop"><svg class="wdw-ni" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="9" cy="20" r="1.5"/><circle cx="18" cy="20" r="1.5"/><path d="M2 3h3l2.5 12h11l2-8H6"/></svg><span>E-commerce</span><svg class="wdw-chev ms-auto" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m9 6 6 6-6 6"/></svg></button><div class="collapse show" id="navShop"><ul class="list-unstyled mb-1 ms-4 ps-3 border-start"><li><a class="wdw-sub" href="#">Products</a></li><li><a class="wdw-sub active" href="#" aria-current="page">Orders</a></li><li><a class="wdw-sub" href="#">Customers</a></li></ul></div></li><li><button class="wdw-nav" type="button" data-bs-toggle="collapse" data-bs-target="#navStats" aria-expanded="false" aria-controls="navStats"><svg class="wdw-ni" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 20V10M10 20V4M16 20v-8M22 20H2"/></svg><span>Analytics</span><span class="badge rounded-pill text-bg-primary ms-2">New</span><svg class="wdw-chev ms-auto" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m9 6 6 6-6 6"/></svg></button><div class="collapse" id="navStats"><ul class="list-unstyled mb-1 ms-4 ps-3 border-start"><li><a class="wdw-sub" href="#">Traffic</a></li><li><a class="wdw-sub" href="#">Revenue</a></li><li><a class="wdw-sub" href="#">Reports</a></li></ul></div></li><li><button class="wdw-nav" type="button" data-bs-toggle="collapse" data-bs-target="#navGeo" aria-expanded="false" aria-controls="navGeo"><svg class="wdw-ni" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="9"/><path d="M3 12h18M12 3c3 3 3 15 0 18M12 3c-3 3-3 15 0 18"/></svg><span>Maps</span><svg class="wdw-chev ms-auto" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m9 6 6 6-6 6"/></svg></button><div class="collapse" id="navGeo"><ul class="list-unstyled mb-1 ms-4 ps-3 border-start"><li><a class="wdw-sub" href="#">Google maps</a></li><li><a class="wdw-sub" href="#">Open street map</a></li></ul></div></li><li><a class="wdw-nav" href="#"><svg class="wdw-ni" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 3H7a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V8l-5-5Z"/><path d="M14 3v5h5"/></svg><span>Documents</span></a></li></ul>
</nav>
<div class="d-flex justify-content-around border-top p-2 mt-2">
<button type="button" class="wdw-tool position-relative" aria-label="Notifications, 3 new"><svg class="wdw-ni" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 8a6 6 0 1 1 12 0c0 7 3 9 3 9H3s3-2 3-9"/><path d="M10 21h4"/></svg><span class="badge rounded-pill text-bg-danger wdw-pip">3</span></button>
<button type="button" class="wdw-tool position-relative" aria-label="Messages, 7 new"><svg class="wdw-ni" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="5" width="18" height="14" rx="2"/><path d="m3 7 9 6 9-6"/></svg><span class="badge rounded-pill text-bg-danger wdw-pip">7</span></button>
<button type="button" class="wdw-tool" aria-label="Settings"><svg class="wdw-ni" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="3"/><path d="M12 2v3M12 19v3M2 12h3M19 12h3M5 5l2 2M17 17l2 2M19 5l-2 2M7 17l-2 2"/></svg></button>
<button type="button" class="wdw-tool" aria-label="Log out"><svg class="wdw-ni" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"/><path d="m16 17 5-5-5-5M21 12H9"/></svg></button>
</div>
</div>
<main class="flex-grow-1 p-4 p-lg-5 min-w-0">
<div class="d-flex align-items-center gap-3 mb-4">
<button class="btn btn-outline-primary d-lg-none px-3" type="button" data-bs-toggle="offcanvas" data-bs-target="#wdwSide" aria-controls="wdwSide">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true"><path d="M4 7h16M4 12h16M4 17h16"/></svg><span class="visually-hidden">Open menu</span>
</button>
<div>
<span class="wdw-eyebrow">E-commerce</span>
<h1 class="wdw-heading h2 mb-0">Orders</h1>
</div>
</div>
<div class="row g-3 g-lg-4 mb-3 mb-lg-4">
<div class="col-12 col-sm-4"><div class="wdw-card-sm p-4"><small class="wdw-muted">Revenue</small><div class="h3 fw-bold text-body-emphasis mb-1">$48,260</div><small class="text-success fw-semibold">+12.4% this month</small></div></div>
<div class="col-12 col-sm-4"><div class="wdw-card-sm p-4"><small class="wdw-muted">Orders</small><div class="h3 fw-bold text-body-emphasis mb-1">1,284</div><small class="text-success fw-semibold">+4.1% this month</small></div></div>
<div class="col-12 col-sm-4"><div class="wdw-card-sm p-4"><small class="wdw-muted">Refunds</small><div class="h3 fw-bold text-body-emphasis mb-1">23</div><small class="text-danger fw-semibold">+2 this week</small></div></div>
</div>
<div class="row g-3 g-lg-4">
<div class="col-12 col-xl-7">
<section class="wdw-card-sm p-4 h-100" aria-labelledby="wdwChartTitle">
<div class="d-flex justify-content-between align-items-start mb-3">
<div><h2 class="h6 fw-bold text-body-emphasis mb-0" id="wdwChartTitle">Orders per day</h2><small class="wdw-muted">Last 14 days</small></div>
<span class="badge rounded-pill text-bg-primary">+8%</span>
</div>
<svg class="wdw-chart text-primary w-100" viewBox="0 0 280 100" preserveAspectRatio="none" role="img" aria-label="Line chart of daily orders, rising from 40 to 95 over 14 days">
<path d="M0 80 L20 70 L40 74 L60 55 L80 60 L100 48 L120 52 L140 38 L160 44 L180 30 L200 36 L220 22 L240 28 L260 14 L280 8 L280 100 L0 100 Z" fill="currentColor" opacity=".12"/>
<path d="M0 80 L20 70 L40 74 L60 55 L80 60 L100 48 L120 52 L140 38 L160 44 L180 30 L200 36 L220 22 L240 28 L260 14 L280 8" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linejoin="round" stroke-linecap="round" vector-effect="non-scaling-stroke"/>
</svg>
<div class="d-flex justify-content-between small wdw-muted mt-2"><span>Oct 1</span><span>Oct 7</span><span>Oct 14</span></div>
</section>
</div>
<div class="col-12 col-xl-5">
<section class="wdw-card-sm p-4 h-100" aria-labelledby="wdwRecentTitle">
<h2 class="h6 fw-bold text-body-emphasis mb-2" id="wdwRecentTitle">Recent orders</h2>
<ul class="list-group list-group-flush">
<li class="list-group-item bg-transparent px-0 d-flex align-items-center justify-content-between gap-2"><span class="lh-sm"><strong class="d-block text-body-emphasis">#10482 · Maria Lopez</strong><small class="wdw-muted">2 minutes ago</small></span><span class="d-flex align-items-center gap-2"><span class="badge rounded-pill text-success-emphasis bg-success-subtle">Paid</span><span class="fw-semibold">$128</span></span></li>
<li class="list-group-item bg-transparent px-0 d-flex align-items-center justify-content-between gap-2"><span class="lh-sm"><strong class="d-block text-body-emphasis">#10481 · Ken Aoki</strong><small class="wdw-muted">18 minutes ago</small></span><span class="d-flex align-items-center gap-2"><span class="badge rounded-pill text-warning-emphasis bg-warning-subtle">Pending</span><span class="fw-semibold">$64</span></span></li>
<li class="list-group-item bg-transparent px-0 d-flex align-items-center justify-content-between gap-2"><span class="lh-sm"><strong class="d-block text-body-emphasis">#10480 · Sara Nilsen</strong><small class="wdw-muted">1 hour ago</small></span><span class="d-flex align-items-center gap-2"><span class="badge rounded-pill text-success-emphasis bg-success-subtle">Paid</span><span class="fw-semibold">$342</span></span></li>
<li class="list-group-item bg-transparent px-0 d-flex align-items-center justify-content-between gap-2"><span class="lh-sm"><strong class="d-block text-body-emphasis">#10479 · Omar Haddad</strong><small class="wdw-muted">3 hours ago</small></span><span class="d-flex align-items-center gap-2"><span class="badge rounded-pill text-danger-emphasis bg-danger-subtle">Refunded</span><span class="fw-semibold">$89</span></span></li>
</ul>
</section>
</div>
</div>
</main>
</div>
</section>
/* Web Designer Wall library style — shared base for every Bootstrap 5 snippet.
Indigo accent, Plus Jakarta Sans, soft cards, pill buttons. Works in light and dark. */
@import url("https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700;800&display=swap");
:root,
[data-bs-theme="light"] {
--wdw-font: "Plus Jakarta Sans", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
--bs-body-font-family: var(--wdw-font);
--bs-primary: #4f46e5;
--bs-primary-rgb: 79, 70, 229;
--bs-primary-text-emphasis: #3730a3;
--bs-primary-bg-subtle: #eef2ff;
--bs-primary-border-subtle: #c7d2fe;
--bs-link-color: #4f46e5;
--bs-link-color-rgb: 79, 70, 229;
--bs-link-hover-color: #4338ca;
--bs-link-hover-color-rgb: 67, 56, 202;
--bs-focus-ring-color: rgba(79, 70, 229, 0.25);
--bs-border-radius: 0.75rem;
--bs-border-radius-lg: 1rem;
--bs-border-radius-xl: 1.25rem;
--wdw-radius-card: 1.25rem;
--wdw-shadow: 0 1px 2px rgba(16, 24, 40, 0.05), 0 16px 40px -16px rgba(16, 24, 40, 0.22);
--wdw-shadow-sm: 0 1px 2px rgba(16, 24, 40, 0.06), 0 4px 12px -4px rgba(16, 24, 40, 0.12);
--wdw-stage: #f5f6fb;
}
[data-bs-theme="dark"] {
--bs-primary: #818cf8;
--bs-primary-rgb: 129, 140, 248;
--bs-primary-text-emphasis: #c7d2fe;
--bs-primary-bg-subtle: rgba(129, 140, 248, 0.14);
--bs-primary-border-subtle: rgba(129, 140, 248, 0.35);
--bs-link-color: #a5b4fc;
--bs-link-color-rgb: 165, 180, 252;
--bs-link-hover-color: #c7d2fe;
--bs-link-hover-color-rgb: 199, 210, 254;
--bs-focus-ring-color: rgba(129, 140, 248, 0.35);
--wdw-shadow: 0 1px 2px rgba(0, 0, 0, 0.4), 0 16px 40px -16px rgba(0, 0, 0, 0.7);
--wdw-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.4), 0 4px 12px -4px rgba(0, 0, 0, 0.5);
--wdw-stage: #0f1117;
}
body { font-family: var(--wdw-font); -webkit-font-smoothing: antialiased; }
/* Bootstrap compiles its blue into these components; point them at the accent. */
.btn-primary {
--bs-btn-bg: var(--bs-primary); --bs-btn-border-color: var(--bs-primary);
--bs-btn-hover-bg: #4338ca; --bs-btn-hover-border-color: #4338ca;
--bs-btn-active-bg: #3730a3; --bs-btn-active-border-color: #3730a3;
--bs-btn-disabled-bg: var(--bs-primary); --bs-btn-disabled-border-color: var(--bs-primary);
--bs-btn-focus-shadow-rgb: var(--bs-primary-rgb);
}
[data-bs-theme="dark"] .btn-primary { --bs-btn-color: #0f1117; --bs-btn-hover-bg: #a5b4fc; --bs-btn-hover-border-color: #a5b4fc; --bs-btn-hover-color: #0f1117; --bs-btn-active-color: #0f1117; }
.btn-outline-primary {
--bs-btn-color: var(--bs-primary); --bs-btn-border-color: var(--bs-primary);
--bs-btn-hover-bg: var(--bs-primary); --bs-btn-hover-border-color: var(--bs-primary);
--bs-btn-active-bg: var(--bs-primary); --bs-btn-active-border-color: var(--bs-primary);
--bs-btn-focus-shadow-rgb: var(--bs-primary-rgb);
}
.btn { --bs-btn-font-weight: 600; min-height: 44px; display: inline-flex; align-items: center; justify-content: center; gap: .5rem; }
.btn-sm { min-height: 36px; }
.form-control, .form-select { min-height: 44px; border-radius: .75rem; }
.form-control:focus, .form-select:focus, .form-check-input:focus { border-color: rgba(var(--bs-primary-rgb), .6); box-shadow: 0 0 0 .25rem var(--bs-focus-ring-color); }
.form-check-input:checked { background-color: var(--bs-primary); border-color: var(--bs-primary); }
.nav-pills { --bs-nav-pills-link-active-bg: var(--bs-primary); }
.nav { --bs-nav-link-color: var(--bs-secondary-color); --bs-nav-link-hover-color: var(--bs-emphasis-color); }
.pagination { --bs-pagination-active-bg: var(--bs-primary); --bs-pagination-active-border-color: var(--bs-primary); --bs-pagination-color: var(--bs-body-color); --bs-pagination-focus-box-shadow: 0 0 0 .25rem var(--bs-focus-ring-color); }
.progress, .progress-stacked { --bs-progress-bar-bg: var(--bs-primary); }
.list-group { --bs-list-group-active-bg: var(--bs-primary); --bs-list-group-active-border-color: var(--bs-primary); }
.dropdown-menu { --bs-dropdown-link-active-bg: var(--bs-primary); border-radius: .875rem; box-shadow: var(--wdw-shadow-sm); }
.accordion { --bs-accordion-active-bg: var(--bs-primary-bg-subtle); --bs-accordion-active-color: var(--bs-primary-text-emphasis); --bs-accordion-btn-focus-box-shadow: 0 0 0 .25rem var(--bs-focus-ring-color); }
.badge { font-weight: 600; }
/* Library building blocks — use these instead of re-inventing them per snippet. */
.wdw-stage { min-height: 100vh; display: flex; align-items: center; background: var(--wdw-stage); padding-block: 3rem; }
.wdw-card { background: var(--bs-body-bg); border: 1px solid var(--bs-border-color-translucent); border-radius: var(--wdw-radius-card); box-shadow: var(--wdw-shadow); }
.wdw-card-sm { background: var(--bs-body-bg); border: 1px solid var(--bs-border-color-translucent); border-radius: 1rem; box-shadow: var(--wdw-shadow-sm); }
.wdw-aurora { position: relative; color: #fff; background: radial-gradient(60% 55% at 100% 0, #818cf8 0, transparent 70%), radial-gradient(65% 60% at 0 100%, #ec4899 0, transparent 65%), #1e1b4b; }
.wdw-eyebrow { display: inline-block; font-size: .75rem; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; color: var(--bs-primary); }
.wdw-heading { font-weight: 800; letter-spacing: -.02em; color: var(--bs-emphasis-color); }
.wdw-muted { color: var(--bs-secondary-color); }
.wdw-icon { width: 2.75rem; height: 2.75rem; flex: none; display: inline-flex; align-items: center; justify-content: center; border-radius: .875rem; background: var(--bs-primary-bg-subtle); color: var(--bs-primary); }
/* Component */
.wdw-shell { min-height: 100vh; }
.wdw-side { --bs-offcanvas-width: 280px; --bs-offcanvas-bg: var(--bs-body-bg); }
@media (min-width: 992px) { .wdw-side { width: 280px; flex: none; background: var(--bs-body-bg); border-right: 1px solid var(--bs-border-color); box-shadow: 8px 0 32px rgba(15, 23, 42, .07); position: relative; z-index: 1; } }
.min-w-0 { min-width: 0; }
.wdw-nav { width: 100%; display: flex; align-items: center; gap: .75rem; min-height: 44px; padding: .5rem .75rem; border: 0; border-radius: .75rem; background: none; color: var(--bs-secondary-color); font-weight: 600; font-size: .95rem; text-decoration: none; text-align: left; transition: background .2s, color .2s; }
.wdw-nav:hover, .wdw-nav:focus-visible { background: var(--bs-tertiary-bg); color: var(--bs-emphasis-color); }
.wdw-nav.active { background: var(--bs-primary-bg-subtle); color: var(--bs-primary-text-emphasis); }
.wdw-nav .wdw-ni { flex: none; }
.wdw-chev { transition: transform .2s; }
.wdw-nav[aria-expanded="true"] { color: var(--bs-emphasis-color); }
.wdw-nav[aria-expanded="true"] .wdw-chev { transform: rotate(90deg); }
.wdw-sub { display: flex; align-items: center; min-height: 40px; padding: .35rem .75rem; border-radius: .625rem; color: var(--bs-secondary-color); text-decoration: none; font-size: .9rem; transition: color .2s, background .2s, transform .2s; }
.wdw-sub:hover, .wdw-sub:focus-visible { color: var(--bs-primary); background: var(--bs-tertiary-bg); transform: translateX(3px); }
.wdw-dotlive { width: 8px; height: 8px; border-radius: 50%; background: var(--bs-success); box-shadow: 0 0 0 3px rgba(var(--bs-success-rgb), .2); }
.wdw-tool { width: 44px; height: 44px; border: 0; border-radius: .75rem; background: none; color: var(--bs-secondary-color); display: inline-flex; align-items: center; justify-content: center; }
.wdw-tool:hover, .wdw-tool:focus-visible { background: var(--bs-tertiary-bg); color: var(--bs-primary); }
.wdw-pip { position: absolute; top: 2px; right: 0; font-size: .625rem; padding: .25em .5em; }
.wdw-side:focus-visible { outline: 0; }
@media (prefers-reduced-motion: reduce) { .wdw-nav, .wdw-sub, .wdw-chev { transition: none; } }
.wdw-nav.parent-active { color: var(--bs-primary-text-emphasis); }
.wdw-nav.parent-active > .wdw-ni { color: var(--bs-primary); }
.wdw-sub.active { background: var(--bs-primary-bg-subtle); color: var(--bs-primary-text-emphasis); font-weight: 600; }
.wdw-chart { height: 180px; display: block; }
@media (min-width: 1200px) { .wdw-chart { height: 220px; } }
(function () {
function initSidebarActive() {
var side = document.getElementById('wdwSide');
if (!side) return;
var links = side.querySelectorAll('a.wdw-nav, a.wdw-sub');
var parents = side.querySelectorAll('button.wdw-nav[data-bs-toggle="collapse"]');
if (!links.length) return;
links.forEach(function (link) {
link.addEventListener('click', function (e) {
e.preventDefault();
links.forEach(function (l) { l.classList.remove('active'); l.removeAttribute('aria-current'); });
parents.forEach(function (p) { p.classList.remove('parent-active'); });
link.classList.add('active');
link.setAttribute('aria-current', 'page');
var group = link.closest('.collapse');
if (group) {
var btn = side.querySelector('[data-bs-target="#' + group.id + '"]');
if (btn) btn.classList.add('parent-active');
}
});
});
}
initSidebarActive();
})();
<div class="sb-shell" id="sbShell">
<aside class="sb-sidebar" id="sbSidebar" aria-label="Sidebar" data-bs-theme="dark" inert>
<div class="sb-brand">
<a href="#" class="sb-logo"><span class="sb-logo-mark">P</span>Pro Sidebar</a>
<button class="sb-close" type="button" id="sbClose" aria-label="Close sidebar"><svg class="sb-ic" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 6l12 12M18 6 6 18"/></svg></button>
</div>
<div class="sb-user">
<img class="sb-avatar" src="https://i.pravatar.cc/96?img=15" alt="" width="48" height="48">
<div class="sb-user-info">
<strong>John <b>Smith</b></strong>
<span>Administrator</span>
<span class="sb-online"><i aria-hidden="true"></i>Online</span>
</div>
</div>
<div class="sb-search">
<label class="visually-hidden" for="sbSearch">Search menu</label>
<span class="sb-search-ic"><svg class="sb-ic" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="11" cy="11" r="6.5"/><path d="m16 16 4.5 4.5"/></svg></span>
<input type="search" id="sbSearch" placeholder="Search menu" autocomplete="off">
</div>
<nav class="sb-nav" aria-label="Main">
<ul class="sb-list" id="sbList">
<li class="sb-heading">General</li>
<li>
<details class="sb-group" name="sb-nav">
<summary><svg class="sb-ic" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="3" width="7" height="9" rx="1.5"/><rect x="14" y="3" width="7" height="5" rx="1.5"/><rect x="14" y="12" width="7" height="9" rx="1.5"/><rect x="3" y="16" width="7" height="5" rx="1.5"/></svg><span class="sb-label">Dashboard</span><span class="badge theme-warning">New</span><span class="sb-caret"><svg class="sb-ic" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m6 9 6 6 6-6"/></svg></span></summary>
<ul class="sb-sub"><li><a href="#">Dashboard 1 <span class="badge theme-success">Pro</span></a></li><li><a href="#">Dashboard 2</a></li><li><a href="#">Dashboard 3</a></li></ul>
</details>
</li>
<li>
<details class="sb-group" name="sb-nav">
<summary><svg class="sb-ic" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="9" cy="20" r="1.4"/><circle cx="18" cy="20" r="1.4"/><path d="M2 3h3l2.6 12.4a1 1 0 0 0 1 .8h8.9a1 1 0 0 0 1-.8L20 7H6"/></svg><span class="sb-label">E-commerce</span><span class="badge theme-danger">3</span><span class="sb-caret"><svg class="sb-ic" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m6 9 6 6 6-6"/></svg></span></summary>
<ul class="sb-sub"><li><a href="#">Products</a></li><li><a href="#">Orders</a></li><li><a href="#">Credit card</a></li></ul>
</details>
</li>
<li>
<details class="sb-group" name="sb-nav">
<summary><svg class="sb-ic" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m12 3 8 5v8l-8 5-8-5V8z"/><path d="m4 8 8 5 8-5M12 13v8"/></svg><span class="sb-label">Components</span><span class="sb-caret"><svg class="sb-ic" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m6 9 6 6 6-6"/></svg></span></summary>
<ul class="sb-sub"><li><a href="#">General</a></li><li><a href="#">Panels</a></li><li><a href="#">Tables</a></li><li><a href="#">Icons</a></li><li><a href="#">Forms</a></li></ul>
</details>
</li>
<li>
<details class="sb-group" name="sb-nav">
<summary><svg class="sb-ic" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 3v18h18"/><path d="m7 15 4-5 3 3 5-7"/></svg><span class="sb-label">Charts</span><span class="sb-caret"><svg class="sb-ic" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m6 9 6 6 6-6"/></svg></span></summary>
<ul class="sb-sub"><li><a href="#">Pie chart</a></li><li><a href="#">Line chart</a></li><li><a href="#">Bar chart</a></li><li><a href="#">Histogram</a></li></ul>
</details>
</li>
<li>
<details class="sb-group" name="sb-nav">
<summary><svg class="sb-ic" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="9"/><path d="M3 12h18M12 3a14 14 0 0 1 0 18M12 3a14 14 0 0 0 0 18"/></svg><span class="sb-label">Maps</span><span class="sb-caret"><svg class="sb-ic" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m6 9 6 6 6-6"/></svg></span></summary>
<ul class="sb-sub"><li><a href="#">Google maps</a></li><li><a href="#">Open street map</a></li></ul>
</details>
</li>
<li class="sb-heading">Extra</li>
<li><a class="sb-link" href="#"><svg class="sb-ic" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 5a2 2 0 0 1 2-2h13v16H6a2 2 0 0 0-2 2z"/><path d="M4 19V5M9 7h6"/></svg><span class="sb-label">Documentation</span><span class="badge theme-primary">Beta</span></a></li>
<li><a class="sb-link" href="#"><svg class="sb-ic" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="5" width="18" height="16" rx="2"/><path d="M3 10h18M8 3v4M16 3v4"/></svg><span class="sb-label">Calendar</span></a></li>
<li><a class="sb-link" href="#"><svg class="sb-ic" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 7a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/></svg><span class="sb-label">Examples</span></a></li>
<li class="sb-empty" id="sbEmpty" hidden>No results</li>
</ul>
</nav>
<div class="sb-footer">
<a href="#" aria-label="Notifications"><svg class="sb-ic" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 16V11a6 6 0 1 1 12 0v5l2 2H4zM10 21h4"/></svg><span class="badge theme-warning sb-pip">3</span></a>
<a href="#" aria-label="Messages"><svg class="sb-ic" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="5" width="18" height="14" rx="2"/><path d="m3 7 9 6 9-6"/></svg><span class="badge theme-success sb-pip">7</span></a>
<a href="#" aria-label="Settings"><svg class="sb-ic" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="3"/><path d="M12 2v3M12 19v3M2 12h3M19 12h3M5 5l2 2M17 17l2 2M19 5l-2 2M7 17l-2 2"/></svg></a>
<a href="#" aria-label="Log out"><svg class="sb-ic" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 3v9"/><path d="M6.3 6.3a8 8 0 1 0 11.4 0"/></svg></a>
</div>
</aside>
<div class="sb-scrim" id="sbScrim" hidden></div>
<main class="sb-main" id="sbMain">
<header class="sb-top">
<button class="btn-icon" type="button" id="sbOpen" aria-controls="sbSidebar" aria-expanded="true" aria-label="Toggle sidebar"><svg class="sb-ic" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 6h16M4 12h16M4 18h16"/></svg></button>
<div>
<h1 class="fs-xl">Dashboard</h1>
<p class="fs-sm fg-secondary">A responsive sidebar template with collapsible menu groups.</p>
</div>
</header>
<section class="sb-stats" aria-label="Key figures">
<article class="card sb-stat">
<div class="card-body">
<p class="sb-stat-label">Revenue</p>
<p class="sb-stat-value">$48,290</p>
<p class="sb-trend sb-up">+12.4% <span>vs last week</span></p>
</div>
</article>
<article class="card sb-stat">
<div class="card-body">
<p class="sb-stat-label">Orders</p>
<p class="sb-stat-value">1,284</p>
<p class="sb-trend sb-up">+5.1% <span>vs last week</span></p>
</div>
</article>
<article class="card sb-stat">
<div class="card-body">
<p class="sb-stat-label">Visitors</p>
<p class="sb-stat-value">32.6k</p>
<p class="sb-trend sb-up">+18.9% <span>vs last week</span></p>
</div>
</article>
<article class="card sb-stat">
<div class="card-body">
<p class="sb-stat-label">Refunds</p>
<p class="sb-stat-value">23</p>
<p class="sb-trend sb-down">-2.3% <span>vs last week</span></p>
</div>
</article>
</section>
<section class="card sb-activity">
<div class="card-body">
<h2 class="fs-md">Recent activity</h2>
<ul class="sb-acts" role="list">
<li class="sb-act"><span class="sb-dot theme-success" aria-hidden="true"></span><div><strong>Order #10482 paid</strong><span>Maya Collins</span></div><time>2 min ago</time></li>
<li class="sb-act"><span class="sb-dot theme-info" aria-hidden="true"></span><div><strong>New customer registered</strong><span>Omar Haddad</span></div><time>18 min ago</time></li>
<li class="sb-act"><span class="sb-dot theme-danger" aria-hidden="true"></span><div><strong>Refund requested</strong><span>Lena Fischer</span></div><time>1 hr ago</time></li>
<li class="sb-act"><span class="sb-dot theme-warning" aria-hidden="true"></span><div><strong>Product stock low</strong><span>Wireless Keyboard</span></div><time>3 hr ago</time></li>
</ul>
</div>
</section>
</main>
</div>
.sb-shell { --sb-w: 17rem; display: flex; min-height: 100vh; background: var(--bs-bg-1); }
.sb-sidebar { --sb-bg: color-mix(in oklch, var(--bs-bg-1), var(--bs-primary-base) 8%); --sb-bg-2: color-mix(in oklch, var(--bs-bg-3), var(--bs-primary-base) 8%); --sb-fg: var(--bs-fg-2); --sb-fg-dim: var(--bs-fg-3); --sb-fg-strong: var(--bs-fg-1); --sb-line: var(--bs-border-color); position: fixed; inset: 0 auto 0 0; z-index: 40; display: flex; flex-direction: column; width: var(--sb-w); color: var(--sb-fg); background: var(--sb-bg); transform: translateX(-100%); transition: transform .25s ease; }
.sb-shell.is-open .sb-sidebar { transform: none; }
.sb-scrim { position: fixed; inset: 0; z-index: 30; background: rgb(0 0 0 / .5); }
.sb-scrim[hidden] { display: none; }
.sb-ic { flex: none; }
.sb-brand { display: flex; align-items: center; justify-content: space-between; padding: 1.125rem 1.25rem; border-bottom: 1px solid var(--sb-line); }
.sb-logo { display: inline-flex; align-items: center; gap: .625rem; color: var(--sb-fg-strong); font-weight: 700; letter-spacing: -.01em; text-decoration: none; }
.sb-logo-mark { display: grid; place-items: center; width: 1.75rem; height: 1.75rem; color: var(--bs-primary-contrast); background: var(--bs-primary-base); border-radius: .5rem; font-size: .9rem; }
.sb-close { display: grid; place-items: center; width: 2rem; height: 2rem; color: var(--sb-fg); background: none; border: 0; border-radius: .5rem; cursor: pointer; }
.sb-close:hover, .sb-footer a:hover { color: var(--sb-fg-strong); background: var(--sb-bg-2); }
.sb-user { display: flex; align-items: center; gap: .875rem; padding: 1.125rem 1.25rem; border-bottom: 1px solid var(--sb-line); }
.sb-avatar { width: 3rem; height: 3rem; object-fit: cover; border-radius: 50%; }
.sb-user-info { display: flex; flex-direction: column; line-height: 1.4; font-size: .8125rem; color: var(--sb-fg-dim); }
.sb-user-info strong { color: var(--sb-fg-strong); font-weight: 400; font-size: .9375rem; }
.sb-user-info b { font-weight: 700; }
.sb-online { display: inline-flex; align-items: center; gap: .375rem; }
.sb-online i { width: .5rem; height: .5rem; background: var(--bs-success-base); border-radius: 50%; }
.sb-search { position: relative; margin: 1rem 1.25rem .5rem; }
.sb-search-ic { position: absolute; top: 50%; left: .75rem; display: flex; color: var(--sb-fg-dim); translate: 0 -50%; pointer-events: none; }
.sb-search input { width: 100%; padding: .5rem .75rem .5rem 2.25rem; font: inherit; font-size: .875rem; color: var(--sb-fg-strong); background: var(--sb-bg-2); border: 1px solid transparent; border-radius: .625rem; }
.sb-search input::placeholder { color: var(--sb-fg-dim); }
.sb-search input:focus-visible { outline: 2px solid var(--bs-primary-base); outline-offset: 1px; }
.sb-nav { flex: 1; min-height: 0; padding: .5rem .75rem 1rem; overflow-y: auto; }
.sb-list, .sb-sub { margin: 0; padding: 0; list-style: none; }
.sb-empty { padding: 1rem .5rem; font-size: .875rem; color: var(--sb-fg-dim); }
.sb-empty[hidden], .sb-list > li[hidden] { display: none; }
.sb-heading { padding: 1rem .5rem .375rem; font-size: .6875rem; font-weight: 600; letter-spacing: .12em; text-transform: uppercase; color: var(--sb-fg-dim); }
.sb-link, .sb-group > summary { display: flex; align-items: center; gap: .75rem; padding: .5625rem .75rem; font-size: .9375rem; color: var(--sb-fg); text-decoration: none; list-style: none; border-radius: .625rem; cursor: pointer; }
.sb-group > summary::-webkit-details-marker { display: none; }
.sb-link:hover, .sb-group > summary:hover { color: var(--sb-fg-strong); background: var(--sb-bg-2); }
.sb-link:focus-visible, .sb-group > summary:focus-visible, .sb-sub a:focus-visible, .sb-footer a:focus-visible, .sb-close:focus-visible { outline: 2px solid var(--bs-primary-base); outline-offset: 1px; }
.sb-group[open] > summary { color: var(--sb-fg-strong); }
.sb-label { flex: 1; }
.sb-caret { display: flex; color: var(--sb-fg-dim); transition: rotate .2s; }
.sb-group[open] .sb-caret { rotate: 180deg; }
.sb-sub { padding: .125rem 0 .5rem 2.5rem; }
.sb-sub a { display: flex; align-items: center; justify-content: space-between; padding: .375rem .75rem; font-size: .875rem; color: var(--sb-fg-dim); text-decoration: none; border-radius: .5rem; }
.sb-sub a:hover { color: var(--sb-fg-strong); }
.sb-footer { display: flex; justify-content: space-around; padding: .5rem; background: var(--bs-bg-body); border-top: 1px solid var(--sb-line); }
.sb-footer a { position: relative; display: grid; place-items: center; width: 2.5rem; height: 2.5rem; color: var(--sb-fg); border-radius: .625rem; }
.sb-pip { position: absolute; top: 0; right: -.125rem; min-height: 1rem; padding: 0 .3rem; font-size: .625rem; }
.sb-main { flex: 1; min-width: 0; padding: 1rem; }
.sb-top { display: flex; align-items: center; gap: 1rem; margin-bottom: 1.5rem; padding-bottom: 1rem; border-bottom: 1px solid var(--bs-border-color); }
.sb-top h1, .sb-top p, .sb-activity h2 { margin: 0; }
.sb-stats { display: grid; grid-template-columns: repeat(2, 1fr); gap: .75rem; margin-bottom: 1.5rem; }
.sb-stat p { margin: 0; }
.sb-stat-label { font-size: .8125rem; color: var(--bs-fg-3); }
.sb-stat-value { margin-block: .25rem !important; font-size: 1.5rem; font-weight: 700; letter-spacing: -.02em; }
.sb-trend { font-size: .8125rem; font-weight: 600; }
.sb-trend span { font-weight: 400; color: var(--bs-fg-3); }
.sb-up { color: var(--bs-success-base); }
.sb-down { color: var(--bs-danger-base); }
.sb-acts { margin: .75rem 0 0; padding: 0; list-style: none; }
.sb-act { display: flex; align-items: center; gap: .875rem; padding: .75rem 0; border-top: 1px solid var(--bs-border-color); }
.sb-act:first-child { border-top: 0; }
.sb-act div { display: flex; flex: 1; flex-direction: column; min-width: 0; line-height: 1.4; font-size: .9375rem; }
.sb-act div span, .sb-act time { font-size: .8125rem; color: var(--bs-fg-3); }
.sb-dot { flex: none; width: .625rem; height: .625rem; border-radius: 50%; }
.sb-dot { background: var(--bs-theme-base); }
@media (width >= 1024px) {
.sb-sidebar { transform: none; }
.sb-scrim { display: none; }
.sb-close { display: none; }
.sb-main { margin-inline-start: var(--sb-w); padding: 1.5rem 2rem; transition: margin .25s ease; }
.sb-shell.is-collapsed .sb-sidebar { transform: translateX(-100%); }
.sb-shell.is-collapsed .sb-main { margin-inline-start: 0; }
.sb-stats { grid-template-columns: repeat(4, 1fr); }
}
@media (prefers-reduced-motion: reduce) { .sb-sidebar, .sb-main, .sb-caret { transition: none; } }
const initSidebarToggle = () => {
const shell = document.getElementById('sbShell')
const sidebar = document.getElementById('sbSidebar')
const main = document.getElementById('sbMain')
const open = document.getElementById('sbOpen')
const close = document.getElementById('sbClose')
const scrim = document.getElementById('sbScrim')
if (!shell || !sidebar || !open) return
const desktop = window.matchMedia('(width >= 1024px)')
const isShown = () => (desktop.matches ? !shell.classList.contains('is-collapsed') : shell.classList.contains('is-open'))
// A closed sidebar is inert (not focusable, hidden from assistive tech);
// an open mobile drawer makes the page behind it inert.
const sync = () => {
const shown = isShown()
sidebar.inert = !shown
if (main) main.inert = !desktop.matches && shown
open.setAttribute('aria-expanded', String(shown))
if (scrim) scrim.hidden = desktop.matches || !shown
}
const toggle = (force, { restoreFocus = false } = {}) => {
const next = typeof force === 'boolean' ? force : !isShown()
if (desktop.matches) shell.classList.toggle('is-collapsed', !next)
else shell.classList.toggle('is-open', next)
sync()
if (!desktop.matches && next) close?.focus()
else if (restoreFocus) open.focus()
}
open.addEventListener('click', () => toggle())
close?.addEventListener('click', () => toggle(false, { restoreFocus: true }))
scrim?.addEventListener('click', () => toggle(false, { restoreFocus: true }))
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape' && !desktop.matches && isShown()) toggle(false, { restoreFocus: true })
})
desktop.addEventListener('change', sync)
sync()
}
const initMenuSearch = () => {
const input = document.getElementById('sbSearch')
const list = document.getElementById('sbList')
const empty = document.getElementById('sbEmpty')
if (!input || !list) return
input.addEventListener('input', () => {
const q = input.value.trim().toLowerCase()
let heading = null
let headingHasHit = false
let total = 0
const flush = () => { if (heading) heading.hidden = !headingHasHit }
list.querySelectorAll(':scope > li:not(.sb-empty)').forEach((li) => {
if (li.classList.contains('sb-heading')) {
flush()
heading = li
headingHasHit = false
return
}
const hit = !q || li.textContent.toLowerCase().includes(q)
li.hidden = !hit
if (hit) { headingHasHit = true; total++ }
const details = li.querySelector('details')
if (details && q) details.open = hit
})
flush()
if (empty) empty.hidden = total > 0
})
}
initSidebarToggle()
initMenuSearch()
Built on Bootstrap 6.0.0-alpha.1 (ES modules, no jQuery). Load Bootstrap through an import map and run the JavaScript as type="module" — the downloaded file is already set up that way. Alpha releases can still change class names.
Built on Bootstrap 5.3.8 with plain JavaScript — no jQuery. Supports light and dark mode via data-bs-theme.