How to create a table of contents with HTML and CSS
Learn how to use HTML and CSS to build a table of contents
In this article, I’ll explain how to generate a table of contents with automatic numbering using pure HTML and CSS.
CSS counters to the rescue
In the past, I imagine that quite a lot of JavaScript code has been written for this purpose. Luckily, nowadays, the Web platform is more powerful than ever. We can do wonderful things with HTML and CSS alone. For one, counting things!
With CSS counters, we can use and increment variables maintained transparently for us by CSS; allowing us to customize the appearance of our content easily.
The value of a CSS counter can be displayed using counter()
or counters()
in a content property.
Let’s walk through the example provided on MDN:
body {
counter-reset: section;
}
h3::before {
counter-increment: section;
content: "Section " counter(section) ": ";
}
...
<h3>Introduction</h3>
<h3>Body</h3>
<h3>Conclusion</h3>
With the above, each time an h3
tag is added to the document, the CSS counter called section
is incremented using counter-increment
. The first occurrence thus has a value of 1
, the second a value of 2
, etc.
Secondly, the value of that counter is displayed using counter(section)
in the content
property.
Note that counter-reset
allows resetting the value of a specific counter.
But CSS counters are cooler than that!
Nesting CSS counters
CSS counters support nesting. As a matter of fact, a nested counter instance is created automatically for each child element, so there’s no additional configuration needed. How cool is that?
Using the counters
CSS function, we can display all the nested counter values at once and decide which character to use to separate each value.
Check out the example on MDN.
Table of contents example
Since nested CSS counters do exactly what I needed, I’ve decided to use those to create my table of contents.
Here’s the gist of it:
As you can see, this is a simple ol
& ul
nested HTML structure.
To style it, we only need to use the following:
The above uses a CSS counter that I’ve called item
, whose value is reset/incremented when needed and rendered using content
.
This results in the following:
Which is pretty much what I wanted, styling details aside. You can indeed go further, use responsive Web design techniques and adapt the margins and whatnot depending on the available space.
You can find the working example here: https://stackblitz.com/edit/html-css-table-of-contents?file=index.html
You can also take a look at the table of contents of my book to see it in action!
Conclusion
In this article, I’ve quickly introduced CSS counters and explained that they support nesting, making it really straightforward to create a table of contents with automatic numbering using pure HTML and CSS.
That's it for today! ✨
About Sébastien
I am Sébastien Dubois. You can follow me on X 🐦 and on BlueSky 🦋.
I am an author, founder, and coach. I write books and articles about Knowledge Work, Personal Knowledge Management, Note-taking, Lifelong Learning, Personal Organization, and Zen Productivity. I also craft lovely digital products . You can learn more about my projects here.
If you want to follow my work, then become a member.
Ready to get to the next level?
To embark on your Knowledge Management journey, consider investing in resources that will equip you with the tools and strategies you need. Check out the Obsidian Starter Kit and the accompanying video course. It will give you a rock-solid starting point for your note-taking and Knowledge Management efforts.
If you want to take a more holistic approach, then the Knowledge Worker Kit is for you. It covers PKM, but expands into productivity, personal organization, project/task management, and more:
If you are in a hurry, then do not hesitate to book a coaching session with me: