Color mode

Navigation

Navigation is provided by the @riebeckite/plugin-navigation plugin, not by a top-level config section. The plugin produces a semantic model { primary, secondary } and owns the rendering mechanics through SiteNav; the Site decides where each rendered list is placed. primary and secondary express prominence, not placement; there is no header or footer key.

ts
import { defineConfig } from "@riebeckite/core";
import { navigation } from "@riebeckite/plugin-navigation";
 
export default defineConfig({
  site: { title: "My site", baseUrl: "https://example.com" },
  plugins: [navigation()],
});

Rendering

SiteNav from @riebeckite/plugin-navigation renders a resolved tree with the standard rb-nav structure, active-path detection, locale-aware normalization, and the aria-current contract. The Site decides where the tree is placed:

tsx
import { SiteNav } from "@riebeckite/plugin-navigation";
 
<SiteNav
  items={model.primary}
  path={c.req.path}
  language={c.get("htmlLanguage")}
/>;

Pass localizeHref to rewrite hrefs (for example to localize docs links), label to change the landmark label, and class/className to extend the <nav> classes.

Zero-config derivation

Called with no arguments, the plugin derives primary links from the vault's discoverable entries (manifest.discoverableEntries: public and discoverable, excluding draft and non-routable content). It reuses existing Riebeckite information rather than a dedicated vault file:

  • folder structure (a folder becomes a section, and nested folders become children)
  • README / index resolution (an index or README note represents its folder and supplies the folder href)
  • a folder without a README or index renders as a label with no link
  • a root README or index never appears in the navigation
  • page title (falling back to a formatted slug segment)
  • permalink

It requires no Riebeckite-specific vault file (no navigation.md) and no required frontmatter.

Derivation follows the language being rendered. Using the language metadata written by the l10n plugin, entries that share a translation collapse into a single item and only the current language's href is used, so a page under /ja/guide/ never mixes in /en/.... Vaults that do not use l10n keep deriving from every entry.

Pass items to replace the derived primary links. Pass secondary for supplementary links the Site renders less prominently.

ts
navigation({
  items: [
    { label: "Guide", href: "/guide" },
    {
      label: "Notes",
      href: "/notes/planning",
      children: [
        { label: "Planning", href: "/notes/planning" },
        { label: "Writing", href: "/notes/writing" },
      ],
    },
  ],
  secondary: [
    { label: "GitHub", href: "https://github.com/example/site", external: true },
  ],
});

Each link is a NavigationItem.

Field Type Meaning
label string Text shown for the link
href string Destination path or URL
children NavigationItem[] Child items, shown as a submenu
external boolean When true, opens in a new tab

label and href are required on authored items. A derived folder group that has no index note renders as a label only, so href is optional in the derived model.

Placement

The plugin does not decide placement; the Site shell does. In the reference Site, primary appears in the header and secondary in the footer. Some shells skip a href: "/" item because the site title already links home.

Building submenus

Use children to nest navigation.

ts
{
  label: "Notes",
  href: "/notes/planning",
  children: [
    { label: "Planning", href: "/notes/planning" },
    { label: "Writing", href: "/notes/writing" },
  ],
}

children render as a submenu.

Linking to external sites

Add external: true for links to other sites.

ts
{
  label: "GitHub",
  href: "https://github.com/example/site",
  external: true,
}

The link opens in a new tab and gets rel="noreferrer".

Marking the current page

The link for the page currently being viewed becomes active automatically.

For example, with:

ts
{ label: "Guide", href: "/guide" }

the item is active on pages such as:

text
/guide
/guide/getting-started
/en/guide
/en/guide/getting-started

Trailing slashes and a leading locale are normalized during matching, so you do not need to worry about differences such as /guide/ and /en/guide.

An active link gets aria-current="page".

An href that does not start with / (such as an external URL) and items with external: true are never treated as active.

On mobile

On narrow viewports, the site navigation collapses into a Menu disclosure.

The content and HTML structure do not change; only the CSS presentation changes with viewport width.

Validation

navigation options are validated while the plugin is loaded.

The main rules are:

  • label is a non-empty string
  • href is a non-empty string
  • external, when present, is a boolean
  • children must not contain an ancestor item

Invalid configuration fails while the plugin is loaded.

Plugin pages are not added automatically

The plugin derives links from the vault's discoverable entries. It does not surface plugin-generated pages on its own.

For example, the following are not added automatically:

  • Search
  • Tag / Folder indexes
  • Taxonomy pages
  • Plugin page types
  • Breadcrumbs
  • Backlinks
  • Related Posts
  • Other content graph features

To show a page a plugin provides, add a link to that page in navigation({ items }).

For the division of responsibility between navigation and plugins, see Customizing your site.

Exported helpers and types

@riebeckite/plugin-navigation exports navigation, buildNavigation, resolveSiteNavigation, NAVIGATION_PLUGIN_NAME, the SiteNav rendering primitive, and the types NavigationItem, NavigationOptions, SiteNavigation, and SiteNavProps.

History

1 changesCollapseExpand
1 + ---
2 + title: Navigation
3 + sidebar:
4 + label: Navigation
5 + order: 10
6 + ---
7 +
8 + # Navigation
9 +
10 + Navigation is provided by the **`@riebeckite/plugin-navigation`** plugin, not by a top-level config section. The plugin produces a semantic model `{ primary, secondary }` and owns the rendering mechanics through `SiteNav`; the **Site decides where each rendered list is placed**. `primary` and `secondary` express prominence, not placement; there is no `header` or `footer` key.
11 +
12 + ```ts
13 + import { defineConfig } from "@riebeckite/core";
14 + import { navigation } from "@riebeckite/plugin-navigation";
15 +
16 + export default defineConfig({
17 + site: { title: "My site", baseUrl: "https://example.com" },
18 + plugins: [navigation()],
19 + });
20 + ```
21 +
22 + ## Rendering
23 +
24 + `SiteNav` from `@riebeckite/plugin-navigation` renders a resolved tree with the standard `rb-nav` structure, active-path detection, locale-aware normalization, and the `aria-current` contract. The Site decides where the tree is placed:
25 +
26 + ```tsx
27 + import { SiteNav } from "@riebeckite/plugin-navigation";
28 +
29 + <SiteNav
30 + items={model.primary}
31 + path={c.req.path}
32 + language={c.get("htmlLanguage")}
33 + />;
34 + ```
35 +
36 + Pass `localizeHref` to rewrite hrefs (for example to localize docs links), `label` to change the landmark label, and `class`/`className` to extend the `<nav>` classes.
37 +
38 + ## Zero-config derivation
39 +
40 + Called with no arguments, the plugin derives `primary` links from the vault's **discoverable entries** (`manifest.discoverableEntries`: public and discoverable, excluding draft and non-routable content). It reuses existing Riebeckite information rather than a dedicated vault file:
41 +
42 + - folder structure (a folder becomes a section, and nested folders become `children`)
43 + - README / index resolution (an `index` or `README` note represents its folder and supplies the folder `href`)
44 + - a folder without a README or index renders as a label with no link
45 + - a root README or index never appears in the navigation
46 + - page `title` (falling back to a formatted slug segment)
47 + - `permalink`
48 +
49 + It requires **no Riebeckite-specific vault file** (no `navigation.md`) and **no required frontmatter**.
50 +
51 + Derivation follows the language being rendered. Using the language metadata written by the `l10n` plugin, entries that share a translation collapse into a single item and only the current language's `href` is used, so a page under `/ja/guide/` never mixes in `/en/...`. Vaults that do not use `l10n` keep deriving from every entry.
52 +
53 + ## Manual and supplementary links
54 +
55 + Pass `items` to replace the derived `primary` links. Pass `secondary` for supplementary links the Site renders less prominently.
56 +
57 + ```ts
58 + navigation({
59 + items: [
60 + { label: "Guide", href: "/guide" },
61 + {
62 + label: "Notes",
63 + href: "/notes/planning",
64 + children: [
65 + { label: "Planning", href: "/notes/planning" },
66 + { label: "Writing", href: "/notes/writing" },
67 + ],
68 + },
69 + ],
70 + secondary: [
71 + { label: "GitHub", href: "https://github.com/example/site", external: true },
72 + ],
73 + });
74 + ```
75 +
76 + ## NavigationItem
77 +
78 + Each link is a `NavigationItem`.
79 +
80 + | Field | Type | Meaning |
81 + | --- | --- | --- |
82 + | `label` | `string` | Text shown for the link |
83 + | `href` | `string` | Destination path or URL |
84 + | `children` | `NavigationItem[]` | Child items, shown as a submenu |
85 + | `external` | `boolean` | When `true`, opens in a new tab |
86 +
87 + `label` and `href` are required on authored items. A derived folder group that has no index note renders as a label only, so `href` is optional in the derived model.
88 +
89 + ## Placement
90 +
91 + The plugin does not decide placement; the Site shell does. In the reference Site, `primary` appears in the header and `secondary` in the footer. Some shells skip a `href: "/"` item because the site title already links home.
92 +
93 + ## Building submenus
94 +
95 + Use `children` to nest navigation.
96 +
97 + ```ts
98 + {
99 + label: "Notes",
100 + href: "/notes/planning",
101 + children: [
102 + { label: "Planning", href: "/notes/planning" },
103 + { label: "Writing", href: "/notes/writing" },
104 + ],
105 + }
106 + ```
107 +
108 + `children` render as a submenu.
109 +
110 + ## Linking to external sites
111 +
112 + Add `external: true` for links to other sites.
113 +
114 + ```ts
115 + {
116 + label: "GitHub",
117 + href: "https://github.com/example/site",
118 + external: true,
119 + }
120 + ```
121 +
122 + The link opens in a new tab and gets `rel="noreferrer"`.
123 +
124 + ## Marking the current page
125 +
126 + The link for the page currently being viewed becomes active automatically.
127 +
128 + For example, with:
129 +
130 + ```ts
131 + { label: "Guide", href: "/guide" }
132 + ```
133 +
134 + the item is active on pages such as:
135 +
136 + ```text
137 + /guide
138 + /guide/getting-started
139 + /en/guide
140 + /en/guide/getting-started
141 + ```
142 +
143 + Trailing slashes and a leading locale are normalized during matching, so you do not need to worry about differences such as `/guide/` and `/en/guide`.
144 +
145 + An active link gets `aria-current="page"`.
146 +
147 + An `href` that does not start with `/` (such as an external URL) and items with `external: true` are never treated as active.
148 +
149 + ## On mobile
150 +
151 + On narrow viewports, the site navigation collapses into a `Menu` disclosure.
152 +
153 + The content and HTML structure do not change; only the CSS presentation changes with viewport width.
154 +
155 + ## Validation
156 +
157 + `navigation` options are validated while the plugin is loaded.
158 +
159 + The main rules are:
160 +
161 + - `label` is a non-empty string
162 + - `href` is a non-empty string
163 + - `external`, when present, is a boolean
164 + - `children` must not contain an ancestor item
165 +
166 + Invalid configuration fails while the plugin is loaded.
167 +
168 + ## Plugin pages are not added automatically
169 +
170 + The plugin derives links from the vault's discoverable entries. It does not surface plugin-generated pages on its own.
171 +
172 + For example, the following are not added automatically:
173 +
174 + - Search
175 + - Tag / Folder indexes
176 + - Taxonomy pages
177 + - Plugin page types
178 + - Breadcrumbs
179 + - Backlinks
180 + - Related Posts
181 + - Other content graph features
182 +
183 + To show a page a plugin provides, add a link to that page in `navigation({ items })`.
184 +
185 + For the division of responsibility between navigation and plugins, see [Customizing your site](../../guides/customizing-your-site.md#navigation).
186 +
187 + ## Exported helpers and types
188 +
189 + `@riebeckite/plugin-navigation` exports `navigation`, `buildNavigation`, `resolveSiteNavigation`, `NAVIGATION_PLUGIN_NAME`, the `SiteNav` rendering primitive, and the types `NavigationItem`, `NavigationOptions`, `SiteNavigation`, and `SiteNavProps`.
190 +