Sidebar
Sidebar — the vertical navigation panel of an application or a documentation site: a scrollable column of grouped links, with a heading over each group.
Examples
<nav class="sidebar nav nav-vertical" aria-label="Documentation"
style="block-size: 22rem; inline-size: 16rem">
<div class="sidebar-header">
<p class="sidebar-title">mostlycss</p>
</div>
<div class="sidebar-group">
<h2 class="sidebar-heading" id="sidebar-start">Getting started</h2>
<ul class="nav-list" aria-labelledby="sidebar-start">
<li><a class="nav-link" href="#install">Installation</a></li>
<li><a class="nav-link" href="#tokens" aria-current="page">Tokens</a></li>
<li><a class="nav-link" href="#skins">Skins and modes</a></li>
</ul>
</div>
<div class="sidebar-group">
<h2 class="sidebar-heading" id="sidebar-components">Components</h2>
<ul class="nav-list" aria-labelledby="sidebar-components">
<li><a class="nav-link" href="#button">Button</a></li>
<li><a class="nav-link" href="#nav">Nav</a></li>
</ul>
</div>
</nav>The links are the nav component — this file is only the panel around them.
.nav on the root is what puts the --nav-* tokens in scope, so retuning link padding here is one declaration rather than a second set of tokens with the same job. The size is inline here because this is a demo: .sidebar sets no width and no height, on purpose, and .sidebar-sticky measures itself against the viewport — which is right in a page shell and turns a boxed example into a full-height column. The next example is the real placement.
Installing
A single link tag is the whole integration.
<div class="docs-layout">
<nav class="sidebar nav nav-vertical" aria-label="Documentation">
<div class="sidebar-group">
<h2 class="sidebar-heading" id="g1">Guides</h2>
<ul class="nav-list" aria-labelledby="g1">
<li><a class="nav-link" href="#a" aria-current="page">Installing</a></li>
<li><a class="nav-link" href="#b">Theming</a></li>
</ul>
</div>
</nav>
<article>
<h2>Installing</h2>
<p>A single link tag is the whole integration.</p>
</article>
</div>The sidebar sets no width at all. One line in your own sheet does it: .docs-layout { display: grid; grid-template-columns: 16rem minmax(0, 1fr); }. Layout primitives are out of scope for this library.
Tokens 21
Level 2, declared on .sidebar itself. Set any of them on that selector to restyle this component without touching the skin.
| Token | Default |
|---|---|
| --sidebar-edge-padding-block | var(--space-3) |
| --sidebar-gap | var(--space-6) |
| --sidebar-offset | 0px |
| --sidebar-padding-block | var(--space-4) |
| --sidebar-padding-inline | var(--space-3) |
| --sidebar-scroll-padding | var(--space-4) |
| --sidebar-title-color | var(--color-on-surface) |
| --sidebar-title-font-family | var(--font-primary) |
| --sidebar-title-font-size | var(--font-size-base) |
| --sidebar-title-font-weight | var(--font-weight-semibold) |
| --sidebar-heading-color | var(--color-on-surface-muted) |
| --sidebar-heading-font-family | var(--font-primary) |
| --sidebar-heading-font-size | var(--font-size-xs) |
| --sidebar-heading-font-weight | var(--font-weight-semibold) |
| --sidebar-heading-letter-spacing | normal |
| --sidebar-heading-margin-block-end | var(--space-1) |
| --sidebar-heading-padding-inline | var(--space-3) |
| --sidebar-bg | var(--color-surface) |
| --sidebar-border-color | var(--color-border-subtle) |
| --sidebar-border-width | var(--border-width) |
| --sidebar-color | var(--color-on-surface) |
Variants and states
Variants
.sidebar-flush.sidebar-lg.sidebar-sm.sidebar-sticky.sidebar-sunken
Inside it
.sidebar-footer.sidebar-header.sidebar-end.sidebar-group.sidebar-heading.sidebar-title
State it reads
None.
Before you ship it
What you have to do 5 requirements
- Name the landmark.
aria-labelon the<nav>. A docs page has a primary nav too, and two unnamednavigationlandmarks are indistinguishable. - Give the sidebar a height, or it will not scroll. Independent scrolling needs something to overflow.
.sidebar-stickyis the usual answer; without it, constrainblock-sizeyourself. Theoverflow-y: autohere is inert on an unconstrained element, which is the correct fallback: the panel grows and the page scrolls. - Set
--sidebar-offsetunder a sticky navbar..sidebar-stickypins to the top of the viewport; a fixed bar above it needs its height subtracted, or the first group hides behind it. - Give each heading an
idand point its list'saria-labelledbyat it. Unique per page — repeated ones silently label the wrong group. - Mark the current page with
aria-current="page", once, on the anchor.
src/css/components/sidebar.css · npx mostlycss add sidebar