Nav is a flat set of links. It appears in a Site Header, inside a nav Drawer on small screens, and in a footer — the same markup in all three, with orientation as the only difference.
It is deliberately not the docs sidebar's tree nav. That one has collapsible sections, sublists and an active trail, and is a different component that happens to also be navigation; its classes are .sidebar-nav-* and it belongs to the docs site rather than the design system. If you need a hierarchy, you do not need this.
Anatomy
nav.nav data-orientation="horizontal" | "vertical"
a.nav-link aria-current="page" on the current item
Links are direct children. There is no list wrapper: a horizontal row of five links is not a list a reader needs announced as one, and the extra element only makes the flex layout harder to reason about.
Basic usage
<nav class="nav" aria-label="Main">
<a class="nav-link" href="/work" aria-current="page">Work</a>
<a class="nav-link" href="/studio">Studio</a>
<a class="nav-link" href="/journal">Journal</a>
<a class="nav-link" href="/contact">Contact</a>
</nav>
aria-label on the <nav> is required when a page has more than one navigation landmark, which is nearly always true once there is a header and a footer.
Orientation
Horizontal is the default. Vertical is what a drawer or a footer column uses.
<nav class="nav" data-orientation="vertical" aria-label="Main">
...
</nav>
Horizontal links never wrap — a wrapped link inside a header changes the bar's height. Vertical links wrap freely, because a column has the width to spare.
Composition
In a site header
The nav sits between the header's start and end slots.
<header class="site-header">
<div class="site-header-inner">
<div class="site-header-start">
<a class="site-header-logo" href="/">…</a>
</div>
<nav class="nav" aria-label="Main">
<a class="nav-link" href="/work" aria-current="page">Work</a>
<a class="nav-link" href="/studio">Studio</a>
</nav>
<div class="site-header-end">
<button class="button header-action" data-icon-only aria-label="Account">…</button>
</div>
</div>
</header>
Below 768px the header hides its nav, on the assumption the same links are reachable from a drawer. If you put a nav in a header, give it a drawer too.
In a drawer
Same links, vertical, inside the drawer the header's menu button opens.
<dialog id="main-nav" class="drawer" data-placement="start" aria-label="Main navigation">
<div class="drawer-header">
<button class="button close-btn" data-icon-only data-size="small"
data-drawer-close aria-label="Close navigation">…</button>
</div>
<div class="drawer-body">
<nav class="nav" data-orientation="vertical" aria-label="Main">
<a class="nav-link" href="/work" aria-current="page">Work</a>
<a class="nav-link" href="/studio">Studio</a>
</nav>
</div>
</dialog>
Accessibility
| Requirement | How |
|---|---|
| Landmark | <nav> is the element. Do not use a <div> with role="navigation" when the element exists |
| Multiple navs | aria-label on each <nav>, so "Main" and "Footer" are distinguishable |
| Current page | aria-current="page" on one link, and only one |
| Focus | Inherited from the global focus rule; the component adds no ring of its own |
| Contrast | The current-item treatment is weight plus colour, never colour alone |
The current item is styled from aria-current, not a class. There is no here on purpose: with one attribute doing both jobs, the visible state and the announced state cannot drift apart. A design that highlights the current link but never tells a screen reader is a common and invisible failure.
Usage rules
Do:
- Set
aria-current="page"on exactly one link - Give every
<nav>anaria-labelwhen a page has more than one - Pair a header nav with a drawer, since the header hides it on small screens
- Keep the set short enough to fit without wrapping — a header nav that needs to wrap is a nav that needs a drawer
Don't:
- Don't use this for hierarchical navigation; it has no concept of a section or an active trail
- Don't use
.sidebar-nav-*classes here — those belong to the docs shell, not the design system - Don't mark the current item with a class instead of
aria-current - Don't put non-navigation controls in a
<nav>; a theme toggle is an action and belongs in the header's end slot
CSS reference
This section documents how the component is built. For usage, see the sections above.
Tokens
| Token | Default | What it controls |
|---|---|---|
| Space between links, both orientations | ||
var(--space-s) var(--space-m) |
Link hit area | |
| Resting link colour | ||
| Hover colour | ||
Colour of the aria-current link |
Selectors
| Selector | Purpose |
|---|---|
| Base component, horizontal | |
.nav[data-orientation="vertical"] |
Column variant; stretches links |
| A link | |
.nav-link[aria-current="page"] |
Current page treatment |
.nav:not([data-orientation="vertical"]) .nav-link |
white-space: nowrap, horizontal only |
Key rules
Layout: flex, gap: var(--nav-gap). Vertical switches flex-direction to column and align-items to stretch.
Current item: colour plus font-weight: var(--font-weight-semi-bold), keyed off the ARIA attribute.
Nothing sets width, position or background — the container owns all three, which is what lets one component serve a header, a drawer and a footer.
Use in another product
The design system installs once per product:
npm install github:bydefaultstudio/design-system-dist#semver:^4.7.0
This component's styles ship in design-system.css. No JavaScript, nothing else to include.