Nav links

nav.nav

Nav — a list of navigation links.

Examples

A primary nav

View “A primary nav” as
<nav class="nav" aria-label="Primary">
  <ul class="nav-list">
    <li><a class="nav-link" href="#overview" aria-current="page">Overview</a></li>
    <li><a class="nav-link" href="#features">Features</a></li>
    <li><a class="nav-link" href="#integrations">Integrations</a></li>
    <li><a class="nav-link" href="#pricing">Pricing</a></li>
    <li><a class="nav-link" href="#customers">Customers</a></li>
    <li><a class="nav-link" href="#docs">Documentation</a></li>
    <li><a class="nav-link" href="#changelog">Changelog</a></li>
    <li><a class="nav-link" href="#support">Support</a></li>
  </ul>
</nav>

Eight destinations, because four in a row is not a navigation bar and an example that shows four proves nothing about how the row wraps, how the current item reads among its neighbours, or how much room the whole thing wants.

The current page is aria-current="page" on the anchor, and there is no .is-active beside it: the attribute that announces the current page is the same one that fills it, so the two can never disagree.

Stacked, and grouped — this is the sidebar you are looking at

View “Stacked, and grouped — this is the sidebar you are looking at” as
<nav class="nav nav-vertical" aria-label="Account settings">
  <ul class="nav-list">
    <li><a class="nav-link" href="#profile">Profile</a></li>
    <li><a class="nav-link" href="#billing" aria-current="page">Billing and invoices</a></li>
    <li><a class="nav-link" href="#members">Members and roles</a></li>
    <li><a class="nav-link" href="#tokens">API tokens</a></li>
    <li><a class="nav-link" href="#webhooks">Webhooks</a></li>
    <li><a class="nav-link" href="#audit">Audit log</a></li>
    <li><a class="nav-link" href="#danger">Delete this workspace</a></li>
  </ul>
</nav>

This component is the navigation in this site’s own sidebar — .nav, .nav-vertical, .nav-list, .nav-link and the aria-current="page" rule, with sidebar.css supplying only the column, the group headings and the scrolling around it.

That is not a coincidence: .sidebar-group-title, .sidebar-list and .sidebar-link used to exist as docs-only copies, and the day they were deleted in favour of these classes is the day the docs started testing the real component. .nav-vertical stacks it and nothing else changes; the anchor becomes display: flex so the current item fills the row rather than hugging its label.

Three sizes

View “Three sizes” as
<nav class="nav nav-sm" aria-label="Footer">
  <ul class="nav-list">
    <li><a class="nav-link" href="#terms">Terms</a></li>
    <li><a class="nav-link" href="#privacy">Privacy</a></li>
    <li><a class="nav-link" href="#cookies">Cookies</a></li>
    <li><a class="nav-link" href="#status">Status</a></li>
  </ul>
</nav>
<nav class="nav" aria-label="Sections, default size">
  <ul class="nav-list">
    <li><a class="nav-link" href="#work">Work</a></li>
    <li><a class="nav-link" href="#studio">Studio</a></li>
    <li><a class="nav-link" href="#journal">Journal</a></li>
  </ul>
</nav>
<nav class="nav nav-lg" aria-label="Sections, large">
  <ul class="nav-list">
    <li><a class="nav-link" href="#work2">Work</a></li>
    <li><a class="nav-link" href="#studio2">Studio</a></li>
    <li><a class="nav-link" href="#journal2">Journal</a></li>
  </ul>
</nav>

The sizes change the link’s type and its padding, never its target: every row clears the touch floor at all three.

.nav-sm is for chrome — a footer, a sidebar, a strip of secondary links — and .nav-lg for a marketing header where the navigation is one of the two things on the page.

Tokens 15

Level 2, declared on .nav itself. Set any of them on that selector to restyle this component without touching the skin.

Level 2 tokens declared by nav
TokenDefault
--nav-gapvar(--space-1)
--nav-hover-bgvar(--color-surface-sunken)
--nav-hover-colorvar(--color-on-surface)
--nav-link-bgtransparent
--nav-link-colorvar(--color-on-surface-muted)
--nav-link-font-familyvar(--font-secondary)
--nav-link-font-sizevar(--font-size-sm)
--nav-link-font-weightvar(--font-weight-medium)
--nav-link-min-sizevar(--target-size-compact)
--nav-link-padding-blockvar(--space-2)
--nav-link-padding-inlinevar(--space-3)
--nav-link-radiusvar(--radius-field)
--nav-current-bgtransparent
--nav-current-colorvar(--color-primary)
--nav-current-font-weightvar(--font-weight-semibold)

Variants and states

Variants

  • .nav-lg
  • .nav-sm

Inside it

  • .nav-link
  • .nav-bare
  • .nav-list
  • .nav-vertical

State it reads

Read from the platform, never mirrored into a class that could disagree with it.

  • :focus
  • :hover

Before you ship it

What you have to do 1 requirements

  1. Name the nav. A page with more than one <nav> needs aria-label on each one ("Primary", "Footer"), or they are announced as several identical landmarks. Put .nav-link on the <a> itself and not on the <li>: the reset only clears the UA link styling for anchors that carry a class, so a nav styled through a descendant selector comes back underlined and blue. Mark the current page with aria-current="page", and mark exactly one. It is the accessible signal as well as the visual one; a class would be a second source of truth that can disagree with it.

src/css/components/nav.css · npx mostlycss add nav