Intro

This is a tutorial on how to add a table of contents to your Jekyll website. The table of contents will be automatically generated based on the headings in your markdown file. It will also highlight the current section you are reading.

What we want is: (1) customizable, (2) automatically highlight the current section, (3) as a sidebar.

Final Result

This is what the table of contents looks like after you complete this tutorial.

toc result

Libraries Used

Tutorial

Step 1

Download jekyll-table-of-contents as toc.js in your js folder.

Then modify the classes setting in toc.js to be:

classes: {
  list: 'nav nav-pills nav-stacked',
  item: '',
  link: ''
}

so that the elements can be found by Bootstrap’s scrollspy.

Step 2

Add the following to your head.html file

<!-- jquery -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.1/jquery.min.js"></script>

<!-- bootstrap -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>

<!-- toc -->
<script src="/js/toc.js"></script>

Step 3

Add <div id="toc"></div> and corresponding js function to your html file.

For my website, I added it to default.html like this:

<div id="toc-wrapper">
  <div id="toc"></div>
</div>

<script type="text/javascript">
  $(document).ready(function () {
    $("#toc").toc({ listType: "ul" });
  });
</script>

Step 4

Set up Bootstrap’s scrollspy by modifing your body tag like this:

<body data-spy="scroll" data-target="#toc" data-offset="75"></body>

Step 5

Add css code for the table of contents sidebar to make it sticks on the right side of the page and appears properly.

This depends on the layout of your website. For my website, I added the following:

Issue for Non-English Header

If your post contains non-english header, the automated highlighting won’t work preperly.

For example, if you have this Chinese header in your post markdown:

## 21 法师的故事

It will be converted to:

<h2 id="21-法师的故事" class="clickable-header">21 法师的故事</h2>

And the corresponding link in the table of contents generated by jekyll-table-of-contents will be:

<a class="" href="#21-%E6%B3%95%E5%B8%88%E7%9A%84%E6%95%85%E4%BA%8B">21 法师的故事</a>

As you can see, the non-english characters are converted to url encoded format. This will cause the Bootstrap’s scrollspy highlighting to fail.

Related Github issues:

In April 2023, this pull request claimed to fix this issue for French, but when I tried bootstrap 5.3, it still doesn’t work for Chinese header.

What’s worse, there’s another bug that make highlighting fail, even for English header mixed with numbers and spaces!

Therefore, until July 2023, there’s no way to make the highlighting work properly for non-english header.