Nav
nav is the single primitive refrakt uses for every kind of structural navigation — sidebars, header menubars, footer link columns, and section landing pages. The content model is identical in every case (grouped or flat lists of links / page slugs); the layout attribute selects the presentation.
Basic usage
Define groups with headings and page slugs as list items. Items before the first heading become top-level items rendered above any groups.
{% nav %}
- [Documentation](/docs/getting-started)
## Getting Started
- [Getting started](/docs/getting-started)
- [Configuration](/docs/configuration/overview)
## Reference
- [CLI overview](/docs/cli/cli-overview)
- [Inspect](/docs/cli/inspect)
{% /nav %}<nav data-rune="nav" data-source-path="runes/nav.md">
<div data-name="top-level">
<ul>
<li data-field="item" data-rune="nav-item">
<a href="/docs/getting-started">
<span data-field="slug">Documentation</span>
</a>
</li>
</ul>
</div>
<section data-field="group" data-rune="nav-group">
<h2 id="getting-started" data-field="title">Getting Started</h2>
<div data-name="panel">
<ul>
<li data-field="item" data-rune="nav-item">
<a href="/docs/getting-started">
<span data-field="slug">Getting started</span>
</a>
</li>
<li data-field="item" data-rune="nav-item">
<a href="/docs/configuration/overview">
<span data-field="slug">Configuration</span>
</a>
</li>
</ul>
</div>
</section>
<section data-field="group" data-rune="nav-group">
<h2 id="reference" data-field="title">Reference</h2>
<div data-name="panel">
<ul>
<li data-field="item" data-rune="nav-item">
<a href="/docs/cli/cli-overview">
<span data-field="slug">CLI overview</span>
</a>
</li>
<li data-field="item" data-rune="nav-item">
<a href="/docs/cli/inspect">
<span data-field="slug">Inspect</span>
</a>
</li>
</ul>
</div>
</section>
</nav>Getting Started
Reference
<rf-nav class="rf-nav" data-source-path="runes/nav.md" data-elevation="flush" data-rune="nav" data-density="compact">
<div data-name="top-level" class="rf-nav__top-level">
<ul>
<li data-field="item" class="rf-nav-item" data-rune="nav-item" data-density="full">
<a href="/docs/getting-started" class="rf-nav-item__link">
<span data-field="slug">Documentation</span>
</a>
</li>
</ul>
</div>
<section data-field="group" class="rf-nav-group" data-rune="nav-group" data-density="full">
<h2 id="getting-started" data-field="title">Getting Started</h2>
<div data-name="panel" class="rf-nav-group__panel">
<ul>
<li data-field="item" class="rf-nav-item" data-rune="nav-item" data-density="full">
<a href="/docs/getting-started" class="rf-nav-item__link">
<span data-field="slug">Getting started</span>
</a>
</li>
<li data-field="item" class="rf-nav-item" data-rune="nav-item" data-density="full">
<a href="/docs/configuration/overview" class="rf-nav-item__link">
<span data-field="slug">Configuration</span>
</a>
</li>
</ul>
</div>
</section>
<section data-field="group" class="rf-nav-group" data-rune="nav-group" data-density="full">
<h2 id="reference" data-field="title">Reference</h2>
<div data-name="panel" class="rf-nav-group__panel">
<ul>
<li data-field="item" class="rf-nav-item" data-rune="nav-item" data-density="full">
<a href="/docs/cli/cli-overview" class="rf-nav-item__link">
<span data-field="slug">CLI overview</span>
</a>
</li>
<li data-field="item" class="rf-nav-item" data-rune="nav-item" data-density="full">
<a href="/docs/cli/inspect" class="rf-nav-item__link">
<span data-field="slug">Inspect</span>
</a>
</li>
</ul>
</div>
</section>
</rf-nav>Each list item is a page slug (e.g., getting-started). Slugs resolve at build time against the nav's source file — a {% nav %} in site/content/docs/_layout.md resolves - getting-started to /docs/getting-started. The page's title frontmatter becomes the link text.
For pages in subdirectories, write a multi-segment slug: themes/configuration resolves to /extend/theme-authoring/configuration. For external URLs or anything outside the nav's source directory, use an explicit Markdown link [Label](/path). Full rules and the build error format are documented in Nav slug resolution.
Each rendered page evaluates every nav against its current URL. The exact-match item gets aria-current="page"; the longest-strict-prefix item (if any) gets data-active="ancestor". Themes style both — Lumina ships visually-distinct treatments by default.
Layouts
The layout attribute switches the presentation. All four layouts accept the same group + items content model.
Vertical (sidebar)
The default — vertical sidebar with groups stacked top to bottom. This is the layout you place in your _layout.md nav region.
{% nav %}
## Getting Started
- [Getting started](/docs/getting-started)
- [Configuration](/docs/configuration/overview)
## Authoring
- [Runes](/runes/rune-catalog)
- [Themes](/themes/themes-catalog)
{% /nav %}<nav data-rune="nav" data-source-path="runes/nav.md">
<section data-field="group" data-rune="nav-group">
<h2 id="getting-started" data-field="title">Getting Started</h2>
<div data-name="panel">
<ul>
<li data-field="item" data-rune="nav-item">
<a href="/docs/getting-started">
<span data-field="slug">Getting started</span>
</a>
</li>
<li data-field="item" data-rune="nav-item">
<a href="/docs/configuration/overview">
<span data-field="slug">Configuration</span>
</a>
</li>
</ul>
</div>
</section>
<section data-field="group" data-rune="nav-group">
<h2 id="authoring" data-field="title">Authoring</h2>
<div data-name="panel">
<ul>
<li data-field="item" data-rune="nav-item">
<a href="/runes/rune-catalog">
<span data-field="slug">Runes</span>
</a>
</li>
<li data-field="item" data-rune="nav-item">
<a href="/themes/themes-catalog">
<span data-field="slug">Themes</span>
</a>
</li>
</ul>
</div>
</section>
</nav>Getting Started
Authoring
<rf-nav class="rf-nav" data-source-path="runes/nav.md" data-elevation="flush" data-rune="nav" data-density="compact">
<section data-field="group" class="rf-nav-group" data-rune="nav-group" data-density="full">
<h2 id="getting-started" data-field="title">Getting Started</h2>
<div data-name="panel" class="rf-nav-group__panel">
<ul>
<li data-field="item" class="rf-nav-item" data-rune="nav-item" data-density="full">
<a href="/docs/getting-started" class="rf-nav-item__link">
<span data-field="slug">Getting started</span>
</a>
</li>
<li data-field="item" class="rf-nav-item" data-rune="nav-item" data-density="full">
<a href="/docs/configuration/overview" class="rf-nav-item__link">
<span data-field="slug">Configuration</span>
</a>
</li>
</ul>
</div>
</section>
<section data-field="group" class="rf-nav-group" data-rune="nav-group" data-density="full">
<h2 id="authoring" data-field="title">Authoring</h2>
<div data-name="panel" class="rf-nav-group__panel">
<ul>
<li data-field="item" class="rf-nav-item" data-rune="nav-item" data-density="full">
<a href="/runes/rune-catalog" class="rf-nav-item__link">
<span data-field="slug">Runes</span>
</a>
</li>
<li data-field="item" class="rf-nav-item" data-rune="nav-item" data-density="full">
<a href="/themes/themes-catalog" class="rf-nav-item__link">
<span data-field="slug">Themes</span>
</a>
</li>
</ul>
</div>
</section>
</rf-nav>Menubar (header)
Horizontal bar where each group becomes a desktop dropdown trigger. Top-level items (before the first ##) render flat as the primary links. Below the breakpoint the whole menubar collapses behind a hamburger button that the rune emits automatically.
{% nav layout="menubar" %}
- [Docs](/docs)
- [Blog](/blog)
## Product
- features
- runes
## Resources
- about
- changelog
{% /nav %}
Interaction (click to open, Escape / outside-click to close, full keyboard model) ships in @refrakt-md/behaviors — no per-page wiring needed.
Columns (footer)
Column grid where each group becomes a footer column with the heading as the column title. Stacks to one column on narrow viewports.
{% nav layout="columns" %}
## Product
- features
- runes
## Resources
- about
- blog
- changelog
## Legal
- [Privacy](/privacy)
- [Terms](/terms)
{% /nav %}
Cards (section landing)
Card grid for section landing pages. Each item is enriched at build time with the linked page's title, description, and icon from frontmatter — no per-item authoring required. Group headings become section titles above each card cluster.
{% nav layout="cards" %}
- getting-started
- runes
- layouts
- theming
{% /nav %}
Combine with auto to list the current page's children without naming each one:
{% nav layout="cards" auto=true /%}
External-URL items render as title-only cards with no enrichment.
Strip (compact secondary nav)
Flat horizontal row of items — no groups, no panels. Use as a persistent secondary nav below the menubar, or nested inside a menubar panel footer slot for per-panel secondary links. Strip is flat by design and warns on ## headings.
{% nav layout="strip" %}
- [Changelog](/releases)
- [Roadmap](https://plan.refrakt.md/refrakt-md/refrakt)
- [Status](https://status.refrakt.md)
{% /nav %}
Rich menubar panels and column flow
Menubar ## groups accept any block content — paragraphs, blockquotes, images, and nested {% nav %} runes — with a position-based intro / footer slot rule. The columns layout gains a ----between-sections column-flow rule plus a headingless mode for use inside menubar panels. Composed together they cover Linear / Vercel / Stripe-style mega menus without a separate mega layout.
See Rich menubar panels and column flow for the full composition guide.
Collapsible sidebars
Add the collapsible modifier on a vertical nav to turn each group into a disclosure. The group containing the current page automatically expands on page load; all others start collapsed. Click a group title to toggle.
{% nav collapsible=true %}
## Getting Started
- getting-started
- install
## Authoring
- runes
- layouts
- theming
{% /nav %}
For the rare case where multiple groups should open by default, pass defaultOpen with a comma-separated list of group titles:
{% nav collapsible=true defaultOpen="Getting Started, Reference" %}
The keyboard model and ARIA wiring (role="button", aria-expanded, aria-controls, focus ring) ship in @refrakt-md/behaviors.
Frontmatter fields used by cards
The cards layout reads the following from each linked page's frontmatter:
---
title: Getting Started
description: Install refrakt and build your first site
icon: rocket
---
title— card heading. Required for sensible output.description— card body. Optional; the card renders title-only when missing.icon— icon name resolvable by the{% icon %}rune. Optional; the card renders without an icon when missing.
Mobile behaviour
Lumina handles responsive behaviour without any author work:
menubarcollapses behind a hamburger button below the breakpoint. The button is emitted by the rune itself — themes show it via media query.columnsstacks into a single column on narrow viewports.cardsshifts to a single column below ~500px.vertical collapsibleworks the same on every viewport — the collapse / expand model is viewport-agnostic.
Attributes
| Attribute | Type | Required | Description |
|---|---|---|---|
ordered | boolean | — | Use numbered list for navigation items |
auto | boolean | — | Automatically generate from child pages |
layout | "vertical" | "menubar" | "columns" | "cards" | "strip" | — | Presentation layout: sidebar (vertical), horizontal menubar (header), column grid (footer), cards (section landing), or strip (compact secondary nav). Defaults to vertical. |
collapsible | boolean | — | Make each group collapsible. The group containing the current page auto-expands; others start collapsed. Only meaningful for vertical layout. |
defaultOpen | string | — | Comma-separated group titles to expand by default, overriding the URL-driven auto-open behaviour. |
Universal attributes
bg
The background layer (SPEC-088): image, video, gradient, flat overlay wash and legibility scrim, in a single injected layer behind the rune's content.
| Attribute | Type | Required | Description |
|---|---|---|---|
bg | string | — | Background preset applied to this block |
bg-from | string | — | Gradient start colour — a semantic token name (→ var(--rf-color-*)) |
bg-gradient | "to-t" | "to-b" | "to-l" | "to-r" | "to-tr" | "to-br" | "to-bl" | "to-tl" | — | Gradient direction (bounded named set) |
bg-gradient-type | "linear" | "radial" | "conic" | — | Gradient type |
bg-to | string | — | Gradient end colour — a semantic token name |
bg-via | string | — | Optional middle gradient stop — a semantic token name |
scrim | "top" | "bottom" | "left" | "right" | "none" | — | Scrim direction (heaviest edge); presence turns the scrim on, "none" opts out of the default cover scrim |
scrim-blur | "none" | "sm" | "md" | "lg" | — | Frost scrim blur amount |
scrim-strength | "sm" | "md" | "lg" | — | Gradient scrim strength |
scrim-tone | "dark" | "light" | — | Whether the scrim darkens (for light text) or lightens (for dark text) |
scrim-type | "gradient" | "frost" | — | Scrim treatment: gradient (default) or frost (backdrop blur) |
elevation
The chrome/depth ladder (SPEC-107). The skin maps each rung to a chrome bundle by attribute, so there is no BEM class.
| Attribute | Type | Required | Description |
|---|---|---|---|
elevation | "sunken" | "flush" | "flat" | "raised" | "floating" | "overlay" | "none" | "sm" | "md" | "lg" | — | Surface depth on the SPEC-107 ladder (sunken→overlay); none/sm/md/lg are deprecated aliases |
inset
Internal padding override.
| Attribute | Type | Required | Description |
|---|---|---|---|
inset | "flush" | "tight" | "default" | "loose" | "breathe" | — | Inner padding of this block |
motion
Scroll-reveal entrance (SPEC-105). The author declares the character, the theme owns the choreography, a behaviour owns the timing.
| Attribute | Type | Required | Description |
|---|---|---|---|
reveal | "none" | "fade" | "slide" | "scale" | "blur" | — | Scroll-reveal entrance character (none|fade|slide|scale|blur); the theme owns the choreography |
stagger | boolean | — | Cascade this block's items in as it reveals (no-op on single-child runes) |
spacing
Block-level rhythm override.
| Attribute | Type | Required | Description |
|---|---|---|---|
spacing | "flush" | "tight" | "default" | "loose" | "breathe" | — | Vertical spacing above and below this block |
substrate
Generated pattern fills (SPEC-087). Markers only — the engine sets the attributes and cell/opacity custom properties, CSS draws the pattern.
| Attribute | Type | Required | Description |
|---|---|---|---|
substrate | "dots" | "grid" | "lines" | "cross" | "checker" | "none" | — | Generated surface pattern |
substrate-fill | "inherit" | "inset" | — | Surface fill the pattern sits on (full colour stays with tint) |
substrate-opacity | "sm" | "md" | "lg" | — | Pattern ink strength |
substrate-size | "sm" | "md" | "lg" | — | Pattern cell size |
substrate-target | "self" | "media" | — | Which surface the pattern fills (overrides the rune/theme default) |
tint
Per-rune colour override (SPEC-053): a named tint from the theme registry, with inline per-token overrides layered on top.
| Attribute | Type | Required | Description |
|---|---|---|---|
tint | string | — | Color tint preset applied to this block |
tint-mode | "auto" | "dark" | "light" | — | Whether the tint adapts to auto, dark, or light mode |
width
The track a block rune occupies.
| Attribute | Type | Required | Description |
|---|---|---|---|
width | "compact" | "narrow" | "content" | "wide" | "full" | — | Maximum width constraint for this block |
| Not available | Why |
|---|---|
| dropcap, reading | this rune declares no prose body |
| frame | this rune declares neither a `frameTarget` nor a media section |
| prominence | this rune has no page-section header |