Add an Automatic Table of Contents in Hugo
A table of contents helps with a long technical article and gets in the way of a short one. Hugo already knows the Markdown heading structure, so the implementation is one template value rather than a JavaScript library.
Hugo has already built the outline
In a single-page template, output:
{{ .TableOfContents }}
Given headings such as:
## First section
### Smaller section
## Second section
Hugo produces a nested list of links to the generated heading IDs. For example:
## Browser support
may render as:
<h2 id="browser-support">
Browser support
</h2>
The table of contents points to that ID and stays in sync when the headings change.
Make it an article-level choice
Not every post needs an outline occupying the top of the page. I prefer an explicit front matter value:
toc: true
Then the template can add a label and navigation landmark only where requested:
{{ if .Params.toc }}
<aside class="toc">
<h2>Contents</h2>
{{ .TableOfContents }}
</aside>
{{ end }}
This keeps short notes short without inventing a fragile heading-count check in the template.
Include useful heading levels
The page title is normally the H1, while article sections begin at H2. A practical Hugo configuration includes H2 and H3:
[markup.tableOfContents]
startLevel = 2
endLevel = 3
ordered = false
Going much deeper can turn the outline into a second article. If a table of contents needs five nested levels, I would first check whether the article structure is doing too much.
Keep the presentation modest
Hugo normally emits markup containing:
<nav id="TableOfContents">
<ul>
...
</ul>
</nav>
The wrapper from the template gives it a styling hook:
.toc {
padding: 1rem;
border: 1px solid #ddd;
}
.toc ul {
padding-left: 1.25rem;
}
.toc a {
text-decoration: none;
}
On wide layouts, a sticky sidebar can work well:
.toc {
position: sticky;
top: 2rem;
}
On a phone, that same sidebar can consume most of the useful screen. A normal block near the article opening is often enough, or it can be collapsed with native HTML:
<details class="toc">
<summary>Contents</summary>
...
</details>
Heading render hooks can also add direct # links beside headings, which is useful when readers share a particular section.
I enable a table of contents for guides that are long enough to need navigation, not because every article template has an empty space for one. Hugo makes it cheap to generate; editorial judgment still decides where it helps.
comments
No comments yet.