# Navigation menus
Navigation has two parts: the **horizontal tabs** (in `aardvark.config.yaml`) and each
tab's **left-nav menu** (defined in page front matter). The config stays tiny —
no hand-maintained nav tree — and the sidebar is a property of your content. The
tabs are optional: [omit them](#optional-a-site-with-no-tabs) and you get just the
sidebar, or turn a tab into a [dropdown](#dropdown-tabs) when it fronts a deep section.
## Tabs (config)
Each tab gets a `link` and an `id`. The `id` is also the **menu name** that pages
target. Add `icon:` to show a glyph beside the tab label.
```yaml
tabs:
- label: Docs
icon: book-2
link: /
id: docs
- label: Components
icon: components
link: /components/
id: components
```
A tab is highlighted whenever the current page belongs to its menu, so a tab
linked to `/` stays active on its nested sub-pages.
## Dropdown tabs
Give a tab `items:` instead of a `link:` and it becomes a **dropdown** — clicking
the tab opens a menu of child links (hover and keyboard both work, with a no-JS
fallback). Each child takes a `label`, a `link`, and an optional `icon:`. This is
handy when one tab fronts a deep section and you want to expose its sub-areas up
top. Keep the tab's `id:` — it still names the left-nav menu, so your `menu:`
front matter is unchanged and the tab stays lit across the **whole** section, not
only the sub-pages it lists:
```yaml
tabs:
- label: Docs
icon: book-2
id: docs # names the "docs" menu; no `link:`, so this tab is a dropdown
items:
- label: Getting Started
icon: flag
link: /docs/
- label: Authoring
icon: pencil
link: /authoring/templating/
- label: Theming
icon: palette
link: /theming/
- label: Deploy
icon: rocket
link: /deploy/
```
Because the dropdown children are ordinary links, don't give them their own `id:`
unless you mean to open a **separate** menu — an `id` on a child names its own menu
the same way a top-level tab's does. Point children at pages that already live in
the section (the `menu: docs` pages, here) so their landing links stay in sync.
## Optional: a site with no tabs
The horizontal tab bar is optional. **Omit `tabs:` entirely** and no bar renders at
all — every page just shows the left-nav sidebar for [its own menu](#menus-front-matter).
Give a section's `index.md` a `menu:` and the rest of the folder
[auto-joins it](#sections-from-folders); the menu name no longer has to match a tab.
```yaml
# aardvark.config.yaml — no `tabs:` key at all
site:
name: My Docs
```
```yaml
---
# content/guide/index.md
title: Guide
menu: guide # names this section's sidebar; siblings auto-join, no tab needed
---
```
Reach for this when a site is a single flat section (or a handful you'd rather not
surface as tabs) — you keep the content-driven sidebar with zero header chrome.
## Menus (front matter)
Add a page to a tab's left nav with front-matter keys:
| Key | Meaning |
| --- | --- |
| `menu` | The tab `id` this page joins (top-level placement). |
| `parent` | The `id` of the parent entry (nests this page under it). |
| `id` | This entry's id, for children to reference. Defaults to the page's path. |
| `navtitle` | A shorter label for the sidebar and breadcrumbs when the page `title` is too long for the narrow nav. The `
` tag and on-page H1 keep the full `title`. |
| `weight` | Optional ordering override. Siblings list **alphabetically by label** by default; give a page a `weight` to pull it ahead (lowest first). |
| `heading` | A label string rendered above this entry as a section divider; the page itself stays a normal, clickable entry. |
| `icon` | An icon shown to the **left** of this entry's label (see [Icons](#icons)). |
| `heading-icon` | An icon for the `heading` section label above this entry. |
Entries list **alphabetically by their nav label** out of the box, so new pages
slot into place with no bookkeeping. Reach for `weight` only when you want a
specific order — a weighted entry jumps ahead of the alphabetical ones. And when a
page's `title` is too long for the narrow sidebar, give it a short `navtitle`:
```yaml
---
title: Templating & data
navtitle: Templating # short sidebar label; and H1 keep "Templating & data"
menu: docs # joins the "docs" tab's left nav
parent: authoring # nested under the entry whose id is "authoring"
weight: 10 # optional — overrides the alphabetical default
---
```
## Sections from folders
The easy path: give a folder's `index.md` a `menu` (or `parent`), and **every
other file in that folder joins it automatically** — no per-file front matter.
A page's id defaults to its path, so `components/button.md` has id
`components/button` and `modes/index.md` has id `modes`.
```bash
content/components/
index.md # menu: components -> the "Components" section (a real page)
button.md # auto-joins Components
action-icon.md # auto-joins Components
```
## Two kinds of entry, plus labels
- **Leaf** — a page with no children: a plain link.
- **Branch** — a page that has children (e.g. a folder `index.md`): its label
links to its own page, and a **caret** expands/collapses the subtree. Click the
caret to peek inside without navigating.
A `heading:` string adds a **non-clickable section label** above an entry — the
"Getting Started" and "Authoring" labels in this sidebar are leaves whose first
item carries a `heading`, with the rest of the group as plain siblings beneath it.
The current page's ancestor branches render expanded, so the nav is correct even
before JavaScript loads.
## Icons
Use `icon:` on horizontal tabs, dropdown tab children, or pages in the left nav. The
glyph renders to the **left** of that item's label. `heading-icon:` does the same for
the `heading` section label above a left-nav entry — the "Getting Started" group in
this sidebar shows both. A value is read **exactly like an [`{% icon %}`](/components/data-display/icon/) spec** — same sources, same rules:
- **A [Tabler](https://tabler.io/icons) icon name** — a bare lowercase name like `rocket`
or `brand-github` (the default for a bare name). Aardvark bakes Tabler glyphs directly into the
static navigation — from the outline set bundled with aardvark, or your locally installed
`@tabler/icons` package when you've pinned a different `theme.iconVersion` — so they paint with
the page and tint with the link color, with no JavaScript or icon request on the normal path.
- **A Font Awesome class** — explicit, e.g. `fa-solid fa-rocket`, `fab fa-github`.
- **A path to an image** — any `.svg`/`.png`/`.jpg`/… under `static/`, e.g.
`/icons/folder.svg`. Square images read best.
- **An emoji** — any non-ASCII glyph, e.g. `🚀`.
The icon is capped to one line so it never makes the nav row taller.
```yaml
---
title: Quickstart
menu: docs
icon: bolt # a Tabler icon, left of this page's label
heading: Getting Started
heading-icon: fa-solid fa-flag # a Font Awesome glyph, left of the section label above it
---
```
A bare name is a **Tabler** icon — Font Awesome must be written out (`fa-solid fa-bolt`),
exactly as in the [`{% icon %}`](/components/data-display/icon/) tag. Font Awesome glyphs also need the FA
stylesheet loaded: set `theme.fontawesome: true` in `aardvark.config.yaml` (this site does),
or pass a kit/CDN URL to self-host or use Pro. Tabler, image, and emoji icons need none of that.
A custom `theme.iconCdn` is authoritative (it may serve different SVGs): navigation uses its runtime
loader and `vark build` stays quiet. A `theme.iconVersion` that is neither bundled with aardvark nor
installed locally also falls back to the runtime loader — but there `vark build` warns which glyphs
it couldn't bake.