Twitter Email
subspace (/ˈsʌbspɛɪs/)
A Jekyll playground site

A simple Table Of Contents solution for Jekyll

Author: Admin
Title: A simple Table Of Contents solution for Jekyll
Language: en-US
Created: 18:27 on Monday, 18. October 2021
Modified: 01:35 on Thursday, 21. October 2021
Keywords: jekyll, liquid, code, toc, table, contents
Excerpt:

This is a simple but fairly useful solution to display a table of contents for a post or article on a Jekyll site. It does not use additional plugins or other 3rd party software.

Tags: Jekyll
Page layout: no_sidebar
Last modified:
18:27 on Monday, 18. October 2021 | by Admin in Jekyll

Description

It is one of the lesser known features of Jekyll, but very useful for those who write longer articles and the feature requires very little effort to implement. We’re talking about a Table of Contents that will automatically collect all headers in an article and use them to build a hierarchical list aka ToC.

Requirements

The only requirement is to use the Kramdown markdown processor which is the default anyway and there are generally few reasons to change this. Should you need to use a different Markdown implementation for whatever reason, there are third-party plugins to implement ToC functionality. However, the method presented here will not work without Kramdown.

The implementation here requires JavaScript and the following things for optional features. The ToC itself does work without scripts though.

The HTML / Markdown part

Code: (click to select all)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<div class="toc-container" markdown="1">

<h4><span id="toc-header">Table of Contents</span>&nbsp;
    <a href="#toc-skipped"><span title="Skip Table of Contents" class="down_symbol"></span></a>
    <span style="cursor: pointer; float:right;" title="Click to show or hide ToC" id="toc-toggle" class="plusminus_symbol">   
    </span></h4>
{:.no_toc .clickable}

* TOC
{:toc}
</div>
<script>
    if ( Cookies.get('toc-hidden', { path: _slug }) == 'true') {
        $('ul#markdown-toc').hide();
        $('span#toc-header').hide();
    }
</script>
<div id="toc-skipped"></div>

Ideally, you should place this fragment under _includes and include that file at the beginning of your post or article. You can find the markdown „magic” in lines 9 and 10 of the code above. This will generate the Table of contents by pulling all headings (there are 6 levels of headings in kramdown) and generate an unordered list from them. The HTML code for the ToC will then replace the * TOC sequence. Assigning the no_toc CSS class to a heading line will prevent that heading from appearing in the index.

In order to spice it up a bit, I’ve added some optional stuff. First, there is a down arrow next to the header that will skip the ToC. This is useful for long articles when the Table of Contents may contain many entries and thus grows to considerable size. Second, the ToC can be hidden with a toggle button and its visibility status will be saved to a per document Cookie. Lines 12 to 17 in the code above check for the Cookie and hide the ToC before the page is loaded. This feature requires JavaScript and jQuery.

The CSS

Formatting the ToC is up to you, this is just a simple example.

Code: (click to select all)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
ul#markdown-toc, ul#markdown-toc ul {
    margin-bottom: 5px !important;
}
ul#markdown-toc {
    margin-bottom: 20px !important;
}
ul#markdown-toc a {
    font-size: 90% !important;    
}
span#toc-header {
    color: orange !important;
}
/* CSS for the symbols */
/* NOTE: requires Font Awesome web font */

span.plusminus_symbol, span.down_symbol {
    font: normal normal normal 18px/1 FontAwesome !important;
    color: $accent_color;
    margin: 0 4px 0 4px;
}
span.plusminus_symbol:before {
    content: "\e43c";
}
span.down_symbol:before {
    content: "\f13a";
}

JavaScript for the toggle button

This little jQuery fragment is needed to allow the ToC to be toggled visible / invisible. It also remembers the setting in a per document cookie using the unique URL of the current document. It should go to your $(document).ready() function. This is optional though, the ToC generation will work without it.

Code: (click to select all)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// NOTE: _slug contains the page url (page.slug) and is defined elsewhere
// like: var _slug = ... 
$('span#toc-toggle').on('click', function(event) {
  if( $('ul#markdown-toc').is(':hidden') ) {
    $('ul#markdown-toc').fadeIn();
    $('span#toc-header').fadeIn();
    Cookies.set('toc-hidden', 'false', { path: _slug, expires: 1350 });
  } else {
    $('ul#markdown-toc').fadeOut();
    $('span#toc-header').fadeOut();
    Cookies.set('toc-hidden', 'true', { path: _slug, expires: 1350 });
  }       
  return false;
});

Conclusion

While there are probably more powerful solutions out there in form of Jekyll plugins, this is a very simple method of creating a Table of Contents. It’s minimalistic in design and if you skip the optional part (the toggle button) requires very little effort and has almost no dependencies.

Jekyll