Navigation
Blume builds the sidebar from your files, then lets you refine it with frontmatter, folder meta, or config — breadcrumbs and outlines follow along.
Blume builds your sidebar from the file system, then lets you refine it as much — or as little — as you want: page by page, folder by folder, or with one explicit config. Breadcrumbs, previous/next links, and the on-page outline all follow from the same model, with nothing to wire up.
The generated sidebar
By default the sidebar mirrors your content tree:
- folders become groups, files become pages
- a page’s label is its frontmatter
title; a group’s label is the humanized folder name - items sort by numeric prefix, then alphabetically, and a folder’s
indexpage comes first
That’s enough for many sites — everything below is opt-in.
Page label, icon, and badge
Tune how a single page appears in the sidebar from its frontmatter, under sidebar:
sidebar:
label: Quickstart # override the title in the sidebar
icon: rocket # an icon from Blume's built-in set
badge: New # a small label beside the entry
order: 1 # sort position within its group
See Frontmatter for the full page schema.
Folder groups
Each folder becomes a sidebar group. Drop a meta.ts beside its pages to set the group’s title, icon, order, and the order of its children:
import { defineMeta } from "blume";
export default defineMeta({
title: "Guides",
icon: "book-open",
pages: ["configuration", "theming", "deployment"],
});
See Folder meta for every field and computing meta at scan time.
A folder’s meta.title and its own index page’s frontmatter title are resolved independently — translating one under i18n and forgetting the other renders a correct sidebar with a stale <title>/heading on the landing page itself. Blume reports a BLUME_NAV_INDEX_TITLE_MISMATCH warning when they diverge. Untranslated pages filled in from the fallback locale are exempt — their title belongs to the fallback locale, and the fix is translating the page, not editing its frontmatter.
To group pages without adding a URL segment, use a parenthesized folder name — see Pages.
Display modes
navigation.sidebar.display sets how every sidebar group renders:
navigation: {
sidebar: {
display: "flat", // "flat" | "group" | "page"
},
}
flat(default) — a non-collapsible header with its pages listed beneath. Pages that aren’t in any group always list first, above the group sections, so they can’t be mistaken for a group’s children.group— a collapsible<details>disclosure per group. Groups start collapsed by default; a group containing the current page always starts open, so only the section you’re in is expanded. Setcollapsed: falsein folder meta to force a group open regardless.page— each group is a single row that, when clicked, slides the sidebar into a sub-panel showing only that group’s items, with a back arrow at the top. The panel is route-aware, so landing directly on a page inside the group opens straight to it.
A group in an explicit sidebar can override the global mode with its own display.
Ordering
When the sidebar is generated, order is resolved highest priority first:
Config sidebar
An explicit navigation.sidebar replaces the generated tree entirely.
Folder meta
The pages array in meta.ts orders a group.
Frontmatter
sidebar.order on a page.File system
An index page first, then numeric prefixes, then alphabetical by label.
Two siblings that land on the same explicit or numeric order fall back to alphabetical order between themselves — Blume reports a BLUME_DUPLICATE_SIDEBAR_ORDER warning so the tie doesn’t go unnoticed.
Hidden pages
Hide a page from the sidebar — and from previous/next pagination — while keeping it built and reachable by its URL:
sidebar:
hidden: true
Tabs
Render top-level sections as tabs in the header, useful for splitting a large site into distinct areas — say adapters, an API, and AI guides. A tab is highlighted when the current route falls under its path:
navigation: {
tabs: [
{ label: "Adapters", path: "/adapters", icon: "plug" },
{ label: "API", path: "/api", icon: "rocket" },
{ label: "AI", path: "/ai", icon: "sparkles" },
],
}
An enabled OpenAPI or AsyncAPI reference mounts at its route but doesn’t add a tab on its own — point a tab at that route to surface it in the header (and, for the native renderer, to scope its operations sidebar), with whatever label you like:
navigation: {
tabs: [
{ label: "API", path: "/reference" },
],
}
A tab’s path is its section prefix, and it doubles as the link target. A section whose path isn’t a page of its own — a folder with no index.mdx — would link to a 404, so the tab falls back to the first page in the section instead. Set href when you want it to land somewhere else:
navigation: {
tabs: [
{ label: "Changelog", path: "/changelog", href: "/changelog" },
],
}
This matters for routes that aren’t part of the content tree, since the fallback can’t see them: the generated changelog index, or a custom page you added under pages/. Without href, a /changelog tab lands on the newest entry rather than the index. Tabs that don’t set href are unaffected.
Tabs also scope the sidebar: when the current route falls under a tab’s path, the sidebar shows only that section’s pages — so /adapters/* lists the adapters and nothing else. The folder at a tab’s path becomes the section, so this needs no extra config beyond the tabs themselves; structure your content into a folder per tab and point each tab at it.
On a route under no tab (or a tab whose path is /), the sidebar shows the pages that don’t belong to a tab — each tab’s folder is hidden from it, since that section already has its own tab in the header. So a root landing page lists your loose top-level pages while the sectioned content stays behind its tab, mirroring Fumadocs’ root folders. If a route has no pages of its own to show this way, the full tree is shown instead, so the sidebar is never left blank.
Selectors
For switching between whole partitions of a site — a product, a version, or any grouped set of destinations — add a selector. Each renders as a dropdown in the header, showing the option whose path matches the current route:
navigation: {
selectors: [
{
kind: "version",
label: "Version",
items: [
{ label: "v2 (latest)", path: "/v2", icon: "rocket" },
{ label: "v1", path: "/v1" },
],
},
],
}
Each item takes a label, a path, and optional icon, description, and tag. kind (dropdown, product, version, or language) is a hint for how the selector is used; all render the same dropdown.
Featured links
Pin links to the top of the sidebar, above every section — a blog, a changelog, a contact or support page that should always be one click away. Unlike the generated tree, featured links are not scoped by tab: they show on every route, on every breakpoint.
navigation: {
featured: [
{ label: "Blog", href: "https://example.com/blog", icon: "newspaper" },
{ label: "Contact", href: "/contact", icon: "headphones" },
],
}
Each link takes a label, an href, and an optional icon (a built-in icon name, image path/URL, or inline SVG — the same as anywhere else). An href may point anywhere: an external URL opens in a new tab, while an internal route (/contact) is validated against your pages at build time, warning you if nothing matches.
Explicit sidebar
For full control, list explicit items in navigation.sidebar — a bare array is shorthand for sidebar.items, and the object form combines them with a global display. When items are set, Blume uses them verbatim and skips file-system generation:
navigation: {
sidebar: [
"/", // a page, referenced by route
{
label: "Guides", // a group
collapsed: false,
items: ["/configuration", "/configuration/theming"],
},
{ label: "GitHub", href: "https://github.com/owner/repo" }, // an external link
],
}
Each item is a page route (a string), a group (label + items), or a link (label + href). Groups can nest, override the global display mode, and start collapsed.
Repository link
When you set github in your config, Blume shows a GitHub icon in the header — beside the theme toggle — that links to your repository. It’s on by default; hide it with navigation.repo:
navigation: {
repo: false, // hide the header GitHub link (default: true)
}
The link only appears when github is configured, so projects without a repo are unaffected either way.
Breadcrumbs and pagination
These come for free from the sidebar tree — no configuration:
- Breadcrumbs show the current page’s parent group above the title.
- Previous and next links at the foot of each page follow sidebar order, skipping hidden pages.
On this page
A right-rail outline is generated automatically from each page’s ## and ### headings, so long pages stay scannable. On narrower screens, where the right rail is hidden, it collapses into an “On this page” dropdown above the content.
Page actions
Below the table of contents, every page shows a set of quick actions:
- Edit on GitHub — links straight to the source file. Appears once you set
githubin your config. - Scroll to top — smoothly returns to the top of long pages.
- Give feedback — opens a prefilled GitHub issue with an optional reaction and note (also requires
github).
Others hand the page to AI tools — Copy as Markdown and Open in chat — covered in AI.
With export on, an Export action also lets readers download the page as a PDF or EPUB.