A Statamic addon that generates a table of contents from a bard or markdown field in your antlers templates using a modifiers.
- β Generate a table of contents from a bard or markdown field.
- β Supports all heading levels (h1 - h6).
- β Specify a range of heading levels to include in the table of contents.
- β Render the table of contents as an ordered or unordered list.
You can search for this addon in the Tools > Addons
section of the Statamic control panel and click install, or
run the following command from your project root:
composer require doefom/statamic-table-of-contents
The addon provides two modifiers that you can use anywhere in your antlers templates:
toc
: Generates the markup for a table of contents from a given bard or markdown fieldwith_ids
: Adds unique IDs to the headings of the rendered html of a given bard or markdown field
If you want to learn more about Statamic modifiers in general, make sure to check out the official documentation: https://statamic.dev/modifiers
To generate a table of contents that also links to your rendered content, we use both modifiers like this:
{{ content_field | toc }}
{{ content_field | with_ids }}
------------------------------------------------------------------------
<!-- The table of contents generated from {{ content_field | toc }} -->
<ul>
<li><a href="#ingredients">Ingredients</a></li>
<li><a href="#boil-the-pasta">Boil the Pasta</a></li>
<ul>
<li><a href="#spaghetti-only">Spaghetti only</a></li>
</ul>
</ul>
<!--
The content with unique IDs added to the headings,
generated from {{ content_field | with_ids }}
-->
<h2 id="ingredients">Ingredients</h2>
<p>...</p>
<h2 id="boil-the-pasta">Boil the Pasta</h2>
<p>...</p>
<h3 id="spaghetti-only">Spaghetti only</h3>
<p>...</p>
Keep in mind that you should always use both modifiers together to ensure that the table of contents links to the correct headings. Using only one of the modifiers will probably not produce the desired results.
Now let's break down the two modifiers.
The toc
modifier generates a table of contents from a given bard or markdown field.
{{ content_field | toc }}
<ul>
<li><a href="#ingredients">Ingredients</a></li>
<li><a href="#boil-the-pasta">Boil the Pasta</a></li>
<ul>
<li><a href="#spaghetti-only">Spaghetti only</a></li>
</ul>
</ul>
By default, the toc modifier will generate an unordered table of contents with all heading levels included. However, you may specify which heading levels to include and whether to render the table of contents as an ordered or unordered list.
{{ content_field | toc:min_level:max_level:ordered }}
You can specify a range of heading levels to be represented in the table of contents (by default, all heading levels from h1 to h6 are included):
{{ content_field | toc:2:4 }}
This will result in a table of contents that only includes h2, h3, and h4 headings.
If you prefer an ordered list instead of an unordered list, you can do this like so:
{{ content_field | toc:1:6:true }}
<ol>
<li><a href="#ingredients">Ingredients</a></li>
<li><a href="#boil-the-pasta">Boil the Pasta</a></li>
<ol>
<li><a href="#spaghetti-only">Spaghetti only</a></li>
</ol>
</ol>
Note: Make sure to provide min_level
and max_level
as well if you want to render the table of contents as an
ordered list to maintain the correct order of the parameters.
Parameter | Description | Default |
---|---|---|
min_level |
The minimum heading level to include. | 1 |
max_level |
The maximum heading level to include. | 6 |
ordered |
Whether to render the table of contents as an ordered list. | false |
The with_ids
modifier adds unique IDs to each heading of the rendered html of a given bard or markdown field.
{{ content_field | with_ids }}
<h2 id="ingredients">Ingredients</h2>
<p>...</p>
<h2 id="boil-the-pasta">Boil the Pasta</h2>
<p>...</p>
<h3 id="spaghetti-only">Spaghetti only</h3>
<p>...</p>
It also respects duplicate headings by appending a sequential number to the heading id.
<h2 id="onions">Onions</h2>
<p>...</p>
<h3 id="chopping">Chopping</h3>
<p>...</p>
<h2 id="carrots">Carrots</h2>
<p>...</p>
<h3 id="chopping-1">Chopping</h3>
<p>...</p>
There is no built-in way to style the table of contents, and therefore it's totally up to you to style it as you see fit.
If you use the Tailwind typography plugin somewhere in your
project, you could style the table of contents by adding the prose
class to a surrounding element:
<div class="prose">
{{ content_field | toc }}
</div>
Of course, you can also apply individual styles to the table of contents. To do this, you'll probably want to wrap the table of contents in a div as well, apply a class to it, and then style it in your CSS:
<div class="table-of-contents">
{{ content_field | toc }}
</div>
<style>
.table-of-contents ul li a {
...
}
</style>
The benefit of this addon is that you have two modifiers, one to generate the table of contents and another one to add unique ids to your headings. This allows you to structure your site however you like.
<div class="table-of-contents">
{{ content_field | toc }}
</div>
<!-- Do something fancy in between -->
<div class="content">
{{ content_field | with_ids }}
</div>
If you are using sets in you bard field, you will need to handle things a little differently.
You should convert the bard field to HTML first, then decode the HTML entities, and finally apply the toc
modifier.
<div class="table-of-contents">
{{ bard_with_sets | bard_html | decode | toc }}
</div>
When looping through the bard field, you should apply the toc
modifier whenever you handle a text node.
<div class="content">
{{ bard_with_sets }}
{{ if type === 'my_custom_set' }}
...
{{ else }}
{{ text | with_ids }}
{{ /if }}
{{ /bard_with_sets }}
</div>
<div class="table-of-contents">
{{ bard_with_sets | bard_html | decode | toc }}
</div>
<div class="content">
{{ bard_with_sets }}
{{ if type === 'my_custom_set' }}
...
{{ else }}
{{ text | with_ids }}
{{ /if }}
{{ /bard_with_sets }}
</div>
This addon is enthusiastically supported because I rely on it myself and I appreciate all feedback for features or issues you encounter using this addon. If you run into any problems, feel free to open an issue on GitHub.