skip navigation

Table of Contents

To add a table of contents in Hugo you can add the built in variable {{ .TableOfContent }} to a template file, typically the template for regular pages, single.html.

To turn it on or off for a given page first make it condition to be met:

{{ if .Params.toc }}
    {{ .TableOfContents }}
{{ end }}

Then just add the param toc to the frontmatter of pages you want a table of contents to be generated:

toc: true

Multi columns

This generates an unordered list of links to the headings inside a nav element:

<nav id="TableOfContents">
    <ul>
        <li><a href="#heading-text-1">heading-text-1</a></li>
        <li><a href="#heading-text-2">heading-text-2</a></li>
        <li><a href="#heading-text-3">heading-text-3</a></li>
    </ul>
</nav>

Making the columns responsive

The number of list items varies depending on the number of headings on each page. If there are only a few, say 3 or 4, you might prefer a straight vertical list of headings. Using the Every Layout technique a query selector can be created using the nth-last-child() selector to layout multiple columns only when there is a certain number of list items (ie. generated from headings).

Firstly layout the columns:

#TableOfContents ul {
	columns: 3 15em;
	column-gap: 1em;
}

The first line, columns: 3 15em; creates a maximum of 3 columns that are at least 15ems wide.

#TableOfContents ul > li {
	column-span: all;
}

This part makes all those list items span fully across all 3 columns.

The next part does the opposite using the nth-child pseudo-selector. Using :nth-last-child means counting from the end of a list rather than the beginning. How about the n+5 bit? If we used just li:nth-last-child(5) we would only select one item, the fifth from the end of the list. Using n+5 means selecting the fifth element and all those before it.

If there are 5 or fewer items none will be selected.

The final line counts forwards from that fifth-from-the-end item using the general sibling combinator ~. These two selectors mean all list items are selected.

#TableOfContents li:nth-last-child(n+5),  /* selects backwards from the fifth last item */
#TableOfContents li:nth-last-child(n+5) ~ li { /* selects forwards from the fifth last item */
	column-span: none;
}