Build a Manual with Hugo #2: Sidebar and Search — Shaping the Information Architecture

4 min read

In #1 we served our first doc with Hugo and Hextra. When you have one or two posts, structure isn’t a problem. The problem shows up when the docs grow to dozens of pages. With a blog, you just stack the newest posts on top and that’s that, but a manual requires the reader to always know “roughly where in the whole the item I’m looking at sits.” The things that do that job are the sidebar and search.

This series, Build a Manual with Hugo, runs in six parts.

  • #1: From Install to Your First Doc
  • #2: Sidebar and Search — Shaping the Information Architecture ← this post
  • #3: Writing Content — Code Blocks, Mermaid, Callouts
  • #4: Deploying to Cloudflare Pages and Connecting a Domain
  • #5: Multilingual Content and Versioning
  • #6: Maintenance — Search Index, Accessibility, Documentation Culture

This post covers building the sidebar from the folder structure, ordering it with weight, and attaching the top menu and search.

Folders Are the Sidebar #

In Hextra, the sidebar isn’t written out in a separate config file; the folder and file structure under content becomes the sidebar hierarchy directly. Let’s look at the following structure.

content structure
content/
├─ _index.md
└─ docs/
   ├─ _index.md            # "Docs" section
   ├─ getting-started.md
   ├─ configuration.md
   └─ advanced/
      ├─ _index.md         # "Advanced" subsection
      └─ plugins.md

This structure appears in the sidebar as a tree where getting-started and configuration sit under a Docs item, and an Advanced item beneath them in turn contains plugins. Growing your docs becomes a matter of organizing folders.

Creating a Section — _index.md #

The key to making a folder into one bundle (a section) in the sidebar is _index.md. When a folder has an _index.md, Hugo treats that folder as a single section and shows it in the sidebar as an expandable item.

To apply common settings across an entire section, use cascade. For example, to apply Hextra’s docs layout to every page under docs, write it like this.

content/docs/_index.md
---
title: Docs
cascade:
  type: docs
---

Settings passed down with cascade apply to all child pages, so you don’t have to repeat the same value on every page.

Setting the Order — weight #

The default sidebar sort doesn’t match the flow of docs well. A manual has a fixed reading order — “install → configure → advanced” — but the default doesn’t know that order. You specify the order with each page’s weight. The smaller the number, the higher it sits.

content/docs/getting-started.md
---
title: Getting Started
weight: 1
---

Give configuration.md a weight: 2, the next page a weight: 3, and so on — numbering in reading order. It helps to space them out as 10, 20, 30 to leave room for inserting a new page between existing ones later.

Refining the Sidebar — Expand and Exclude #

Deep trees are collapsed by default. To keep a particular section expanded from the start, write the following in that section’s _index.md.

Expand by default
---
title: Docs
sidebar:
  open: true
---

Posts you don’t want to publish yet can be left as draft: true so they drop out of the production build. If you want to keep one in the sidebar but exclude it only from search results, use excludeSearch: true.

Exclude from search
---
title: Internal Note
excludeSearch: true
---

Top Menu — navbar #

If the sidebar is the path within the docs, the top menu (navbar) is the major branches of the whole site. Add items to menu.main in hugo.yaml.

hugo.yaml — top menu
menu:
  main:
    - name: Docs
      pageRef: /docs
      weight: 1
    - name: Search
      weight: 2
      params:
        type: search

pageRef points to a path within the site; if you need an external link, use url instead. Giving params.type: search, as on the Search item, places a search box in that spot.

Attaching Search #

Hextra includes, by default, a search that works without any separate service. FlexSearch builds the doc index at build time and ships it as a static file alongside your site, so no server or external API is needed. You can turn it on and off in hugo.yaml.

hugo.yaml — search
params:
  search:
    enable: true
    type: flexsearch
    flexsearch:
      index: content

One thing worth noting is Korean search. FlexSearch’s default tokenization is geared toward space-delimited languages like English, so for Korean, searching from the middle of a word may return fewer matches. If search quality in your actual docs disappoints, adjust the tokenization options; for large multilingual docs, we’ll look at alternatives like Pagefind together in #6.

Wrapping Up #

In this post we built the sidebar from the folder structure, ordered it with weight, and attached the top menu and the built-in search. Now, even as the docs grow, readers can gauge their position from the sidebar and jump straight to what they want via search.

The next post covers writing content. From code blocks and Mermaid diagrams to callouts that make cautions and warnings stand out, we’ll cover the elements that make docs pleasant to read.

X