Navigation and menus
This page covers the ways a reader moves between pages: the navbar menu, the section switcher, breadcrumbs, page actions, previous / next, and the footer. The sidebar tree and the outline belong to Layouts and page types.
Navigation has no second information architecture: the navbar comes from Hugo’s
menus.main, and the sidebar from the shape of content/. The theme reads no
parallel navigation tree such as a docs.json or a navigation.yaml.
The navbar menu
Top-level entries go in each language’s menus.main:
A lower weight comes first. pageRef points at a site page and url at an
external one; an external link automatically gains target="_blank",
rel="noopener noreferrer" and an external-link mark. identifier is the
stable handle configuration uses to reference the entry (quick_links and
sidebar_root_menu match on it), name is translated per language, and the
identifier is not.
A menu entry can also hang off a page’s front matter, which suits “this page is itself a top-level entry”:
The GitHub entry at the right of the navbar is not a menu item: it comes
from params.github_project_repo (falling back to params.github_repo). A menu
entry identified as github is skipped by the menu area and never shows. To
change that entry’s target, change the repository parameters — see
Repository links and page info.
Dropdowns
Use Hugo’s parent to establish a parent-child relationship. Only one level
of children is supported:
- Every entry is one icon and one title on its own row, in one
moderate-width column. A child’s
params.descriptionis configuration data only; the panel never renders it. - The parent is itself an ordinary link: hovering or focusing it expands the panel, and clicking or pressing Enter goes to the parent page. There is no separate expand arrow, and a touch reader lands on the parent page, whose body lists the same links.
- Keyboard: the down arrow expands and focuses the first item, Esc closes and returns focus to the link, and clicking outside closes it.
- The 0.5
params.columnsparameter is retired: setting it emits a build warning and the panel keeps its single column. - A third level warns at build time and degrades to a static group heading; it does not produce a third-level flyout. Put deeper levels in the sidebar.
Menu icons
Below lg a menu entry is reduced to its icon, so every top-level entry should
have one. Icons resolve in this order:
iconin the target page’s front matter;- The menu entry’s own
params.icon; - A built-in default matched by identifier or section name (
docs,blog,examples,community,about,download,githuband others); fa-solid fa-linkwhen none matched.
An icon is one Font Awesome class pair, with the free faces supplied locally by the theme:
Taxonomy menus
A top-level entry pointing at a taxonomy page (/tags/, /categories/) needs
no hand-written submenu: the panel renders a grid of “term + count” chips,
ordered by descending count.
Enabling taxonomies is in Taxonomies.
Navbar controls
The navbar is 50px tall and holds, left to right: the brand (logo or wordmark), the menu area, search, version, language, theme, GitHub. Home and Landing pages keep a final drawer menu button at the right edge. The navbar renders on every layout; documentation, blog and taxonomy pages use the same controls without that Landing drawer.
The navbar has a full desktop tier and a compact icon tier:
| Viewport | State |
|---|---|
lg and above |
Full: brand, menu entries with text, all utility controls; Home/Landing ends with the drawer button |
Below lg |
Compact: the brand stays, everything else becomes right-aligned icons |
Below md |
Only search and the drawer button remain in the navbar; version, language, theme and keyboard help remain in the footer’s bottom bar |
The individual controls are switched on elsewhere: the search icon needs
params.offline_search (see Search), the version
menu needs params.versions (see Versions), the
language menu appears automatically with two or more languages configured (see
Languages), and the theme control needs
params.ui.dark_mode (see
Brand and appearance).
Auto-hide
With it on, the navbar leaves the normal flow and rests above the viewport, sliding out only when the pointer enters the middle 60% of the area above its original position (or keyboard focus arrives), and it overlays the body rather than pushing it down. 64px at each side is outside the wake zone, so it does not cover the collapsed sidebar and outline restore buttons.
It is disabled automatically below 768px, on a coarse pointer, and on a
touch-only device, where the navbar stays visible. A top-level
navbar_autohide in page front matter or a section cascade overrides it per
section.
Turning the navbar off
It can also be turned off for one page or one section:
With it off, the theme restores the interface the navbar carried: mobile subnavigation, a brand and search row at the top of the sidebar, and utility buttons on the outline rail. The switch suits pages that must own the viewport; it is not a general layout preference. This site’s documentation section uses it: documentation pages navigate through the sidebar, and the navbar is one row too many.
The section switcher
The row at the top of the sidebar is the section switcher, deciding which tree
is shown. Its entries are built in order and deduplicated: every top-level
section → every section anywhere with sidebar_root_for: self → the currently
resolved root.
To let a large subtree become a root of its own (a versioned API reference, a
self-contained handbook), in its _index.md:
self makes the section index and all its descendants use the new tree;
children leaves the index in the parent tree and binds only the descendants.
To keep a top-level section out of the switcher, set sidebar_root_menu: false
in its front matter.
With one entry the switcher degrades to a borderless link; two or more make it a dropdown. The tree below it still has the section index as its first link: the switcher picks a tree, and the root link picks a document.
Breadcrumbs and page actions
An ordinary content page has a breadcrumb row above its title, and that row’s right end carries the page actions. A top-level section omits a single-level breadcrumb that would only repeat the title, and the action buttons stay where they are.
Breadcrumb labels use the localized linkTitle, and the hierarchy matches the
sidebar.
The page action menu
Page actions are the split button at the end of the title row: the left half copies this page’s Markdown in one click (turning into a green tick on success), and the arrow on the right expands the full menu. The menu has two groups — taking the content away, and changing or producing it:
| Action | When it appears |
|---|---|
| Copy as Markdown | The site enabled the markdown output format |
| Open in ChatGPT | page_context_menu.assistant_links: true |
| Open in Claude | The same |
| View Markdown source | The markdown output format |
| View history | params.github_repo can resolve the source path |
| Edit this page | params.github_repo |
| Create child page | params.github_repo |
| Open a documentation issue | params.github_repo |
| Open a project issue | params.github_project_repo |
| Print the whole section | The section enabled the print output format |
The assistant entries are off by default: on a click the full current URL
(query and fragment included) goes to a third party with a localized prompt,
while the body is not uploaded. Before enabling it, confirm no sensitive
information appears in URLs, and disclose the boundary in the privacy statement.
A page can narrow the site policy with a boolean assistant_links in front
matter, but cannot enable it on the site’s behalf.
Custom external actions come last in the menu, and url supports three
URL-encoded placeholders:
The placeholders are {url} (the page’s full address), {title} (the page
title) and {markdown_url} (the Markdown version’s address).
On the blog root section and its first-level subsections, the left half becomes the RSS subscription link while “copy as Markdown” stays in the menu. A page with no Markdown output loses the left half, and the arrow becomes an “Actions” button with a label.
These actions are also entries in the command palette.
The pager
Previous / next at the end of the body are two text links, ordered by the
sidebar’s visible tree: root page → first page → through to the last. The root
has no previous, and the last page has no next. Where a site provides
data/docs_nav.json, that explicit tree decides the paging order too — and the
section index on a docs or book section the file declares, so the sidebar, the
pager and the index can no longer show the same children in three different
orders. A section the file does not declare, and a site without the file, keep
walking the content tree. See
Layouts and page types.
pager_types accepts only docs, book and blog; any other value warns and
is dropped. A page opts out through front matter:
The same order is written into <head>: with a previous or next page, it emits
<link rel="prev"> and <link rel="next"> so browsers and crawlers can see the
reading sequence.
Paging applies to HTML output only. Print, Markdown and RSS have neither the
links nor the two rel relationships.
The pager is the third of the four page-end components (feedback → annotation → pager → comments), in a fixed order with four independent switches.
The footer
The footer’s shape comes from params.ui.footer_style (fat / slim / none
— see Brand and appearance). The fat link
grid reads data/footer/<language>.yaml. It is not a menu, and the theme has no
menus.footer:
- Without
brand.nameandbrand.logoit falls back to the site’s own brand name, logo and wordmark;taglineandsloganrender Markdown. - An internal
urlresolves against the current language root;external: trueopens in a new tab withrel="noopener noreferrer". - The grid has as many columns as the data does.
- A single-language site can use
data/footer.yaml. - With
fatconfigured but no data, it degrades toslimautomatically, so it can be enabled before the content exists.
The fat footer’s copyright row has a collapse arrow at its right end, hiding
or restoring the link grid above it. It starts expanded, and the reader’s choice
is kept in localStorage under td-footer-collapsed across pages. slim and
none have no such button, and it is unrelated to focused reading mode.
Every rendered bottom bar ends with the same icon dock: version, language,
theme, then keyboard help. Each configured menu opens upward; the version
trigger stays icon-only while its choices keep their full labels. The fat
footer’s collapse arrow follows those four controls. The sidebar has no second
copy of the dock, and footer_style: none removes the bar with the footer.
The copyright row and the centre note are parameters — see Configuration.
Verify
After changing navigation, check each of these:
- The build has no
Navbar menu … supports one interactive child levelwarning; one means the menu is three levels deep; - On the desktop: clicking a parent goes to the parent page, hovering expands the panel, and Esc closes it;
- Narrow the window below
lg: every top-level entry still has an icon, and one without an icon is blank at this width; - Below
md: Home and Landing navbars keep search and the drawer button on the right; version, language, theme and keyboard help stay in the persistent footer bottom bar; - The switcher at the top of the sidebar lists every top-level section, with the current one marked;
- On any documentation page, E / Q page in sidebar order, and the page source has matching
rel="prev"/rel="next"; - Open the page action menu and confirm what should be there is, and what should not is not (for example “open a project issue” with no
github_project_repoconfigured).
Related
- Layouts and page types — sidebar tree, outline and shell types
- Configuration — defaults of the navigation parameters
- Command palette — page actions and custom commands
- Repository links and page info — the edit, history and issue links
- Organizing content — how the directory structure decides the sidebar