Nowadays it’s pretty common to have the Table Of Contents on the side, that follows the user’s scrolling. I’ve decided to see what it takes to add it to my Hugo blog.

At first I’ve looked around in the web, whether Hugo already supports it. It seemed to me that it’s not yet available by default, while some themes might support it due to their underlying framework that they use. For example Bootstrap has ScrollSpy.

Inspiration

I’ve found this great article on CSS-tricks by Chris Coyier that gave me a headstart on how it can be simply implemented.

My Tricky Part

For my hugo site I use a modified version of the PaperMod theme. Nowadays I do not follow it’s updates while I have many of my own customizations in it.

Sections

For sticky headers it’s essential to know which item is currently visible in the browser. I hadn’t yet had that info. In markdown I can just embed many headers, and it’s content won’t have any knowledge in the DOM of where it is…

My layout looked like this:

<h1>Title</h1>
<p>Paragraph</p>
<h2>Sub Title</h2>
<p>Another Paragraph</p>
<p>Yet another Paragraph</p>
<h2>Another Title</h2>
<p>Another Paragraph: Tokyo Drift</p>

Instead of something like this:

<section>
    <h1>Title</h1>
    <p>Paragraph</p>
    <section>
        <h2>Sub Title</h2>
        <p>Another Paragraph</p>
        <p>Yet another Paragraph</p>
    </section>
    <section>
        <h2>Another Title</h2>
        <p>Another Paragraph: Tokyo Drift</p>
    </section>
</section>

I wrapped all my headings into sections as it shall be done in the example above with a well/placed regular expression, after the markdown parse has already happened.

It’s usually a bad idea to replace content in HTML with regular expressions. But since I have a generated code it has enough constraints, that I can trust enough to hope that it’s a solid solution.

I added <section> in the beginning, </section> at the end and replaced <h\ds by prefixing </section><section> this way the number of starting and closing tags will always match, and I don’t have to write a more complicated parser, neeither do I have to come up with an algorithm that tries to keeps track of the state of scrolling with limited information.

Table Of Contents

The theme had a toc.html file with complicated logic. In the docs I’ve found, that hugo does it for me already… and lets me use a rather simple {{ .TableOfContents }} variable in the template.

I just needded to style it.

Hide On Smaller Screens

I’m not completely proud of my current solution. I id not want to erwrite the whole layout. At first an absoulute positioned parent seemed feasible, but a good ol’ float: right works exactly I expect it.

Since it’s just a convenience feature I hide it if the sceen is smaller than where this TOC would fit already.

Summary

It was a great practice to get to know hugo better, while creating something fancy.

Happy coding!

Cover Photo by ENESFILM from Pexels