phosphorescent.dev

Table of Contents Shortcode for Zola

2025-06-16
zola tera

To build this website, I'm using a tool called Zola. For my longer posts, I'd like to have a table of contents somewhere on the page for easier navigation, but I don't want it on every page. This could've been achieved by making a separate template for the page with a table of contents, but I wanted something a bit more flexible that lets me insert the table of contents wherever I want. Apparently there's not an easy way to do this, so I've come up with a bit of a hack based on an old GitHub issue.

Zola has functionality called shortcodes which lets you call functions to insert text into your markdown before rendering the markdown into into HTML. Unfortunately, because shortcodes are expanded before the markdown is parsed, they don't have access to the attributes of the page. These attributes are exposed at the template level, but not the shortcode level. So we have to do some tomfoolery.

If we create a shortcode called toc that accepts no arguments and returns a constant string <!-- toc -->, we can then replace that string with a call to a Tera macro that actually generates the HTML for the table of contents. A specific implementation of method can be found in this commit.

Now when we write some markdown, we can insert toc() surrouneded by double curly brackets wherever we want, and we will get a table of contents rendered correctly. Below is an example of what the table of contents for this website will look like.


Table of Contents

Header 1

Subheader 1

Subheader 2

Subheader 3

Header 2

Subheader 4