Sidebar
A composable, themeable and customizable sidebar component.
Usage
HTML + JavaScript
Step 1: Include the JavaScript files
You can either include the JavaScript file for all the components, or just the one for this component by adding this to the <head> of your page:
<script src="https://cdn.jsdelivr.net/npm/basecoat-css@1.0.0/dist/js/basecoat.min.js" defer></script>
<script src="https://cdn.jsdelivr.net/npm/basecoat-css@1.0.0/dist/js/sidebar.min.js" defer></script>
Step 2: Add your sidebar HTML
<aside class="sidebar" data-side="left" aria-hidden="false">
<nav aria-label="Sidebar navigation">
<section class="scrollbar">
<div role="group" aria-labelledby="group-label-content-1">
<h3 id="group-label-content-1">Getting started</h3>
<ul>
<li>
<a href="#">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="m7 11 2-2-2-2" />
<path d="M11 13h4" />
<rect width="18" height="18" x="3" y="3" rx="2" ry="2" />
</svg>
<span>Playground</span>
</a>
</li>
<li>
<a href="#">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M12 8V4H8" />
<rect width="16" height="12" x="4" y="8" rx="2" />
<path d="M2 14h2" />
<path d="M20 14h2" />
<path d="M15 13v2" />
<path d="M9 13v2" />
</svg>
<span>Models</span>
</a>
</li>
<li>
<details id="submenu-content-1-3">
<summary aria-controls="submenu-content-1-3-content">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M12.22 2h-.44a2 2 0 0 0-2 2v.18a2 2 0 0 1-1 1.73l-.43.25a2 2 0 0 1-2 0l-.15-.08a2 2 0 0 0-2.73.73l-.22.38a2 2 0 0 0 .73 2.73l.15.1a2 2 0 0 1 1 1.72v.51a2 2 0 0 1-1 1.74l-.15.09a2 2 0 0 0-.73 2.73l.22.38a2 2 0 0 0 2.73.73l.15-.08a2 2 0 0 1 2 0l.43.25a2 2 0 0 1 1 1.73V20a2 2 0 0 0 2 2h.44a2 2 0 0 0 2-2v-.18a2 2 0 0 1 1-1.73l.43-.25a2 2 0 0 1 2 0l.15.08a2 2 0 0 0 2.73-.73l.22-.39a2 2 0 0 0-.73-2.73l-.15-.08a2 2 0 0 1-1-1.74v-.5a2 2 0 0 1 1-1.74l.15-.09a2 2 0 0 0 .73-2.73l-.22-.38a2 2 0 0 0-2.73-.73l-.15.08a2 2 0 0 1-2 0l-.43-.25a2 2 0 0 1-1-1.73V4a2 2 0 0 0-2-2z" />
<circle cx="12" cy="12" r="3" />
</svg>
<span>Settings</span>
</summary>
<ul id="submenu-content-1-3-content">
<li>
<a href="#">
<span>General</span>
</a>
</li>
<li>
<a href="#">
<span>Team</span>
</a>
</li>
<li>
<a href="#">
<span>Billing</span>
</a>
</li>
<li>
<a href="#">
<span>Limits</span>
</a>
</li>
</ul>
</details>
</li>
</ul>
</div>
</section>
</nav>
</aside>
<main>
<button type="button" onclick="document.getElementById('sidebar')?.toggle()">Toggle sidebar</button>
<h1>Content</h1>
</main>
HTML structure
<aside class="sidebar" aria-hidden="false">- Wraps the sidebar component. Supported attributes:
id: target a specific sidebar from JavaScript methods.aria-hidden: current open state.falsemeans visible,truemeans hidden.data-side: physical side of the viewport. Useleftorright. Defaults toleft.data-initial-open: set tofalseto start closed on desktop.data-initial-mobile-open: set totrueto start open below the breakpoint.data-breakpoint: pixel width used to switch between desktop and mobile behavior. Defaults to768.
<nav aria-label="...">- The semantic navigation landmark inside the sidebar.
<header>Optional- Top area for branding, workspace switchers, or primary controls.
<section>- Scrollable sidebar content.
<div role="group" aria-labelledby="...">- A grouped set of navigation items. Use an
h3with a matchingidwhen the group has a visible label. <ul>/<li>- Navigation list structure. Items may contain an
a, abutton, or adetailssubmenu. <a aria-current="page">- Use
aria-current="page"for the active link. You can also usedata-active="true"for non-link active items. <button type="button">- Use buttons for actions. On mobile, links and buttons close the sidebar unless they include
data-keep-mobile-sidebar-open. <details>/<summary>- Use native disclosure for submenus. The nested
ulcontains the submenu items. <footer>Optional- Bottom area for account controls, settings, or secondary actions.
<main>- The sibling content wrapper. Basecoat applies the desktop margin to the sibling that follows the sidebar.
<button type="button" onclick="document.getElementById('sidebar')?.toggle()">- Calls the sidebar method used to toggle, open, or close the sidebar.
<!-- Server-side or router-driven current item -->
<nav aria-label="Sidebar navigation">
<ul>
<li><a href="/my-path?page=overview">Overview</a></li>
<li><a href="/my-path?page=settings" aria-current="page">Settings</a></li>
<li><button type="button" data-active="true">Active action</button></li>
</ul>
</nav>
Basecoat differences
Basecoat keeps sidebar intentionally smaller than shadcn/ui. It supports fixed left/right sidebars, mobile overlay behavior, grouped navigation, active states, and native details submenus.
It does not currently expose shadcn/ui's React provider, rail, inset/floating variants, icon-only collapse mode, menu actions, menu badges, or menu skeleton API. Those can be composed manually if needed, but they are not part of the Basecoat sidebar contract.
RTL content is supported through logical spacing and borders. The data-side value remains physical: left means the left side of the viewport and right means the right side.
JavaScript API
basecoat:initialized- Once the component is fully initialized, it dispatches a custom (non-bubbling)
basecoat:initializedevent on itself. sidebar.open()- Opens the specific sidebar element.
sidebar.close()- Closes the specific sidebar element.
sidebar.toggle()- Toggles the specific sidebar element.
<!-- Toggles the sidebar -->
<button type="button" onclick="document.getElementById('sidebar')?.toggle()">Toggle sidebar</button>
<!-- Opens the `#main-navigation` sidebar -->
<button type="button" onclick="document.getElementById('main-navigation')?.open()">Open sidebar</button>
<!-- Closes the sidebar -->
<button type="button" onclick="document.getElementById('sidebar')?.close()">Close sidebar</button>
Jinja and Nunjucks
You can use the sidebar() Nunjucks or Jinja macro for this component.
{% set menu = [
{ type: "group", label: "Getting started", items: [
{ label: "Playground", url: "#" },
{ label: "Models", url: "#" },
{ label: "Settings", type: "submenu", items: [
{ label: "General", url: "#" },
{ label: "Team", url: "#" },
{ label: "Billing", url: "#" },
{ label: "Limits", url: "#" }
] }
]}
] %}
{{ sidebar(
label="Sidebar navigation",
menu=menu
) }}
<main>
<h1>Content</h1>
</main>