# Nav

## Overview

Nav is the default visual expression of a plain navigation element in this design system.

The component styles a native `<nav>` with a direct child `<ul>` or `<ol>` as a sticky horizontal row of links.

Users move to another destination through real links; no content is hidden behind tab panels.

Use breadcrumbs for hierarchy trails and pagination for paged result controls.

## When to use

Use nav for visible links between peer destinations such as sections, pages, or documentation areas.

## When not to use

Do not use nav for actions, hierarchy trails, or paged result controls; use buttons, breadcrumbs, or pagination.

## Usage

```html
<nav aria-label="Site">
  <ul>
    <li><a href="/overview">Overview</a></li>
    <li><a href="/tokens" aria-current="page">Tokens</a></li>
    <li><a href="/components">Components</a></li>
  </ul>
</nav>
```

Use this pattern when users need to jump between peer destinations such as sections, pages, or documentation areas while keeping all content visible.

Do not use buttons when the interaction changes location instead of triggering an action.

Use `nav.toc` for in-page table-of-contents navigation:

```html
<nav class="toc" aria-label="On this page">
  <h2>On this page</h2>
  <ul>
    <li><a href="#overview">Overview</a></li>
    <li><a href="#usage">Usage</a></li>
  </ul>
</nav>
```

Current limitation: `.toc` does not automatically highlight a link as its target section becomes current during manual scrolling. CSS [`scroll-target-group`](https://developer.mozilla.org/en-US/docs/Web/CSS/scroll-target-group) and `:target-current` can provide scroll-position-aware highlighting without JavaScript, but they are not yet Baseline Widely Available. Adopt them as a progressive enhancement when they reach that support level.

## Behavior

Covered by [Playwright behavior tests](../../tests/e2e/components.spec.js).

- NAV-001: Nav renders as a single horizontal row of links and allows horizontal overflow on smaller screens instead of wrapping onto multiple lines.
- NAV-002: Links should keep native link semantics instead of using tab roles or button behavior.
- NAV-003: Current-location items should be identified with `aria-current` and remain visually distinct from sibling links.
- NAV-004: The nav is sticky by default, and in-content sticky elements should inherit the shared layout offset so they stop below it instead of sliding underneath it.
- NAV-005: The direct child primary navigation uses a higher stack level than in-page navigation so page-level navs scroll underneath it.
- NAV-006: Comfortable and compact density come from the shared layout tokens for min-height, padding, and gap.
- NAV-007: `.toc` renders in-page navigation as a sticky table of contents at wider viewports without relying on accessible-name text for styling, and its links match dropdown navigation links with full control padding and a subtle background on hover or keyboard focus.
- NAV-008: Default nav styles activate only when the navigation has a direct child `ul` or `ol`, leaving navigation with a different markup contract untouched.
## Accessibility

- Use a native `<nav>` with a clear accessible name through `aria-label` or `aria-labelledby` when the page has more than one navigation landmark.
- Use `.toc` for table-of-contents styling and keep `aria-label` or `aria-labelledby` for the accessible name only.
- Keep destinations as real `<a>` elements so keyboard, history, and assistive technology behavior remain intact.
- Use `aria-current="page"` or `aria-current="location"` on the current destination when it remains a link.
- Do not add ARIA tab roles unless the interface is a real tabbed panel system with the expected keyboard behavior.

## Variables

| Variable | Type | Description |
| --- | --- | --- |
| `--nav-border-color` | `<color>` | Sets the bottom border color for navigation bars; change it when nav needs more or less separation from content. |
| `--nav-color-accent-subtle` | `<color>` | Sets --nav-color-accent-subtle so the component can default to shared theme or layout tokens while exposing an overrideable component API. |
| `--nav-color-focus-ring` | `<color>` | Sets --nav-color-focus-ring so the component can default to shared theme or layout tokens while exposing an overrideable component API. |
| `--nav-control-border-width` | `<length>` | Sets --nav-control-border-width so the component can default to shared theme or layout tokens while exposing an overrideable component API. |
| `--nav-control-gap` | `<length>` | Sets --nav-control-gap so the component can default to shared theme or layout tokens while exposing an overrideable component API. |
| `--nav-control-min-height` | `<length>` | Sets --nav-control-min-height so the component can default to shared theme or layout tokens while exposing an overrideable component API. |
| `--nav-control-padding-block` | `<length>` | Sets --nav-control-padding-block so the component can default to shared theme or layout tokens while exposing an overrideable component API. |
| `--nav-control-padding-inline` | `<length>` | Sets --nav-control-padding-inline so the component can default to shared theme or layout tokens while exposing an overrideable component API. |
| `--nav-current-background` | `<color>` | Sets the background behind the current nav item; change it when the selected page state needs a stronger or subtler surface. |
| `--nav-focus-ring-size` | `<length>` | Sets --nav-focus-ring-size so the component can default to shared theme or layout tokens while exposing an overrideable component API. |
| `--nav-font-family-sans` | `Any` | Sets --nav-font-family-sans so the component can default to shared theme or layout tokens while exposing an overrideable component API. |
| `--nav-font-size` | `<length>` | Sets --nav-font-size so the component can default to shared theme or layout tokens while exposing an overrideable component API. |
| `--nav-line-height` | `<number>` | Sets --nav-line-height so the component can default to shared theme or layout tokens while exposing an overrideable component API. |
| `--nav-link-color` | `<color>` | Sets the default nav link color; change it when nav links should inherit a different page or header context. |
| `--nav-link-current-color` | `<color>` | Sets the current nav item text and underline color; change it when selected navigation should use a different accent. |
| `--nav-link-hover-color` | `<color>` | Sets the hover color for nav links; change it when navigation needs a clearer interactive cue. |
| `--nav-page-min-inline-size` | `<length>` | Sets --nav-page-min-inline-size so the component can default to shared theme or layout tokens while exposing an overrideable component API. |
| `--nav-safe-area-top` | `<length>` | Sets --nav-safe-area-top so the component can default to shared theme or layout tokens while exposing an overrideable component API. |
| `--nav-space-inline` | `<length>` | Sets --nav-space-inline so the component can default to shared theme or layout tokens while exposing an overrideable component API. |
| `--nav-space-stack` | `<length>` | Sets the block gap used by table-of-contents navigation; change it when in-page navigation needs denser or looser item rhythm. |
| `--nav-sticky-offset` | `<length>` | Sets the sticky top offset for table-of-contents navigation; change it when in-page nav needs to clear custom persistent chrome. |

## Depends On

- `--color-accent-subtle`
- `--color-border-subtle`
- `--color-focus-ring`
- `--color-primary-subtle`
- `--color-text`
- `--color-text-accent`
- `--font-family-sans`
- `--font-line-height-body`
- `--font-size`
- `--layout-control-border-width`
- `--layout-control-gap`
- `--layout-control-min-height`
- `--layout-control-padding-block`
- `--layout-control-padding-inline`
- `--layout-focus-ring-size`
- `--layout-page-min-inline-size`
- `--layout-safe-area-top`
- `--layout-space-inline`
- `--layout-space-stack`
- `--layout-sticky-offset`
