zudo-doc supports a navigation hierarchy inspired by Docusaurus:

- **Header nav** — top-level tabs in the site header, with optional dropdown menus
- **Sidebar categories** — collapsible groups in the sidebar
- **Sidebar items** — individual pages within categories

[Dynamic content unavailable in text export]

This page covers the **left-side tabs**. The right-side cluster (appearance menu, GitHub link, etc.) is configured separately — see [Header Right Items](https://zudo-doc.takazudomodular.com/docs/guides/header-right-items).



## Configuration

Define header navigation items in `zfb.config.ts`. Items can be flat links or dropdown parents with nested children:

```ts title="zfb.config.ts"
export default defineConfig(
  zudoDoc({
    // ...
    headerNav: [
      // Flat link (no dropdown)
      { label: "Getting Started", labelKey: "nav.gettingStarted", path: "/docs/getting-started", categoryMatch: "getting-started" },

      // Dropdown parent with children
      {
        label: "Learn",
        labelKey: "nav.learn",
        path: "/docs/guides",
        categoryMatch: "guides",
        children: [
          { label: "Guides", labelKey: "nav.guides", path: "/docs/guides", categoryMatch: "guides" },
          { label: "Components", labelKey: "nav.components", path: "/docs/components", categoryMatch: "components" },
        ],
      },

      { label: "Reference", labelKey: "nav.reference", path: "/docs/reference", categoryMatch: "reference" },
    ],
  }),
);
```

## Properties

### `HeaderNavItem`

| Property | Type | Description |
|----------|------|-------------|
| `label` | string | Display text shown in the header |
| `labelKey` | string (optional) | i18n translation key that overrides `label` when a translation is available |
| `path` | string | URL path the link navigates to |
| `categoryMatch` | string (optional) | Links this header tab to a sidebar category |
| `versioned` | boolean (optional) | Whether this item's link carries the active `/v/{version}` prefix. Default `true` |
| `children` | `HeaderNavChildItem[]` (optional) | Child nav items displayed as a dropdown menu (one level only) |

### `HeaderNavChildItem`

Child items use the same properties as `HeaderNavItem` except they cannot have their own `children`. This enforces a single level of nesting at the type level.

| Property | Type | Description |
|----------|------|-------------|
| `label` | string | Display text shown in the dropdown |
| `labelKey` | string (optional) | i18n translation key |
| `path` | string | URL path the link navigates to |
| `categoryMatch` | string (optional) | Links this child to a separate top-level sidebar category; omit it for nested paths under the parent's category |
| `versioned` | boolean (optional) | Whether this item's link carries the active `/v/{version}` prefix. Default `true` |

### `labelKey`

The `labelKey` property enables localized header navigation labels. When set, zudo-doc looks up the key in the current locale's translation file and uses the translated string instead of `label`. If no translation is found, `label` is used as a fallback.

Translation keys follow the `nav.*` namespace convention (e.g., `"nav.gettingStarted"`, `"nav.guides"`).

### `categoryMatch`

The `categoryMatch` property connects a header tab to a specific sidebar category. When a header tab with `categoryMatch` is active, the sidebar filters to show only the pages within that category.

For example, `categoryMatch: "guides"` links the tab to the `guides/` content directory. When a user navigates to any page under `/docs/guides/`, the "Guides" tab becomes active and the sidebar shows only the guides category.

A [note tray](https://zudo-doc.takazudomodular.com/docs/guides/note-tray) is not a special header-nav type. Add it like any other top-level category: set the item's `path` to the tray index and its single-segment `categoryMatch` to the tray directory name. The tray declaration in `index.mdx` controls its sidebar and listing behavior.

Children can also have `categoryMatch`. For example, placing `categoryMatch: "components"` on a child ensures that visiting `/docs/components/` activates the parent dropdown and filters the sidebar to the components section.

#### Nested Children Under One Category

When every child is nested below one top-level category, keep `categoryMatch` only on the parent. Child active state is resolved from each child's `path`, while the parent's single-segment `categoryMatch` keeps the sidebar scoped to the complete top-level category. Per-package changelogs are the canonical example:

```ts
{
  label: "Changelog",
  path: "/docs/changelog",
  categoryMatch: "changelog",
  children: [
    { label: "Core", path: "/docs/changelog/core" },
    { label: "CLI", path: "/docs/changelog/cli" },
  ],
}
```

[Dynamic content unavailable in text export]

Do not copy the parent's `categoryMatch` onto these children, and do not use a multi-segment value such as `categoryMatch: "changelog/core"`. `categoryMatch` only matches a top-level directory; a multi-segment child value never matches and can empty the sidebar. The build warns when two or more children share the same `categoryMatch` and whenever a parent or child uses a multi-segment value.



### `versioned`

The `versioned` property controls whether an item's link carries the active `/v/{version}` prefix when a version other than the latest is active. It defaults to `true` — most header items point at doc content that has a matching page in every archived version, so their link should switch versions along with the reader.

Set `versioned: false` on any item that points at content with no versioned counterpart — a page that exists only for the latest doc set and is never regenerated inside an archived version directory. Without `versioned: false`, that item's link would 404 whenever an older version is active.

[Dynamic content unavailable in text export]

If your project enables [versioning](https://zudo-doc.takazudomodular.com/docs/guides/versioning), audit every `headerNav` item that links to unversioned content and set `versioned: false` on it. The showcase's own "Claude" and "Codex" header items (from the `claudeResources` and `codexResources` features) are textbook cases: those routes are generated only for the default `docsDir` and never exist inside an archived version directory, so both items set `versioned: false`.



## Dropdown Behavior

Items with `children` render as dropdown menus. The parent item itself remains a clickable link — clicking it navigates to its `path`. The dropdown provides quick access to related sub-pages.

- **Desktop**: opens on hover and closes when the mouse leaves the menu area. A small chevron indicates the dropdown.
- **Keyboard**: opens when the trigger receives focus (via `focus-within`). Press Escape to close. Fully accessible without a mouse.
- **Mobile**: nested items appear as expandable groups in the mobile sidebar menu, with a toggle chevron to expand/collapse children.
- **Overflow**: when the browser window is narrow and a dropdown parent is moved to the overflow "..." menu, its children are shown as indented sub-items.

## Active State

A header nav item is considered active when the current page URL starts with the item's `path`. If the current page matches any child item's `path`, the parent item also shows as active.

For example, visiting `/docs/components/admonitions` activates the "Learn" dropdown because `/docs/components` matches one of its children.

## Mobile Behavior

On small screens (`< 1024px`), the desktop header nav is hidden. The sidebar toggle provides access to all navigation on mobile. Nested navigation items appear as expandable groups in the mobile sidebar — tap the chevron to expand/collapse children.