How to use shortcode headings in the Hugo TOC
Last updated: Mar 22, 2024
“TL:DR: Try using markdown headings in the shortcode and call the shortcode with the percent-sign delimiter. I’m not sure why this works.”
When I write headings, I always consider how they’ll look in the auto-generated table of contents (TOC). If the headings are descriptive, the TOC creates a powerful navigation tool, providing:
- A high-level summary of the overall document
- A set of entry points to help readers find the sections that most relate to them.
I wrote a long post, Most common edits in technical documentation. Because it was so long and regularly structured, I wrote a shortcode to template the content from different data files. When my shortcode content didn’t appear in my TOC for this on this Hugo site, I was sad.
But I accidentally found a solution: write the shortcode in markdown.
Solution: markdown headings
In short:
- Use markdown headings in the shortcode (that’s
##
instead of<h2>
). - Delimit the shortcodes with the percent sign (that’s
%
instead of<
).
Shortcodes with the %
delimiter render before the page.
I don’t know why the headings wouldn’t work with a percent delimiter and HTML
headings, but this is what I’ve found.
For a demonstration, read the next section.
Live demonstration
I’ve written two shortcodes with level-three headings. The only difference is heading style:
The
html-headings
shortcode uses HTML.<h3>HTML heading, {{ (.Get 0) }}-delimited shortcode</h3>
The
markdown-headings
shortcode uses markdown.### Markdown heading, {{ (.Get 0) }}-delimited shortcode
Now, I’ll put the following snippet directly in the file that you’re reading.
{{< toc-demo/html-headings "bracket" >}}
This heading doesn't appear in the TOC.
{{< toc-demo/markdown-headings "bracket" >}}
No heading is created because the angle bracket
causes the shortcode to be processed as HTML.
{{% toc-demo/html-headings "percent" %}}
This heading doesn't appear in the TOC.
{{% toc-demo/markdown-headings "percent" %}}
This heading _appears_ in TOC.
Scroll back up and check yourself!
![Drawing of a confused Jackie Chan](/images/jackie-what.jpg)
Here it comes:
HTML heading, bracket-delimited shortcode
This heading doesn’t appear in the TOC.
### Markdown heading, bracket-delimited shortcodeNo heading is created because the angle bracket causes the shortcode to be processed as HTML.
HTML heading, percent-delimited shortcode
This heading doesn’t appear in the TOC.
Markdown heading, percent-delimited shortcode
This heading appears in TOC. Scroll back up and check yourself!
Discussion
I’m not sure why only Markdown headings work. As far as I can gather, before v0.55, no shortcode content could appear in a TOC, because the markdown parser didn’t process shortcodes in any way. Somehow, though, my HTML headings still get skipped by the part of the application that generates the TOC.
EDIT: with a bit of looking, I believe some better solutions might be to use unsafe = true
in the config, or perhaps, in more complex shortcodes, using RawContent
. If I investigate more, I’ll make a new post.
Related links
This seems to be a common problem in Hugo. Here are some relevant links and issues that I could find.
Hugo 0.55 release notes: Shortcodes revisted
Pulls:
Issues:
- 6690: Shortcode way of including md cause headings missed in TOC
Community posts. I think better solutions are here!