Create a Table of Contents automatically


  • Angela Frey
    Comment actions Permalink

    This script hyperlinks to the header name, which means that if I cross-link from article A to a subsection in article B, if that header name is ever updated the cross-link breaks.

    Is it possible to hyperlink to the header ID instead? For example:

    Header Name hyperlink:


    Header ID hyperlink:


    FWIW, you can find the header ID while editing an article - in Article A, select text, insert link, choose a header in the dropdown, then look at the URL. I was using this method to manually create Tables of Content, which I could then refer to when creating a cross-link from another article to the subsection (just copy the URL). 

  • Vladan Jovic
    Comment actions Permalink

    Hey Iris, glad to hear it works!

    Yes, it is doable to have it on the right or left side but that requires some design/CSS changes in the layout.

    If you have someone in your team familiar with CSS he/she can do that for sure.

  • Duane Knudsen
    Comment actions Permalink

    Vladan, thank you very much for sharing. I've incorporated the code into the article_page.hbs template of our HC and it works great. I had played around a bit with the JS version but couldn't get it to run properly (could be due to a highly customized HC with category accordians, etc). 

    Thanks again for a fantastic ToC solution!

  • Tim Capone
    Comment actions Permalink

    Hey all,


    Just an FYI this line:

    var $anchorname = $heading[0].outerText.replace (/\s/g,'');

    should be changed to:

    var $anchorname = $heading[0].innerText.replace (/\s/g,'');

    This will make it work on Firefox browsers.


    /* ============================================================================================== */
    /* ============================== Custom Article Table of Contents ============================== */
    /* ============================================================================================== */

    var $headers = $('.article-body:first h1');

    if ($headers.length == 0) $headers = $('.article-body:first h2');

    if ($headers.length > 0) {
    var $toc = $('<div class="toc" style="margin-bottom: 25px">');
    var $firstUl = $('<ul>');
    var $currentUl = $firstUl;
    var previous_level = 1;
    var $arrayUl = [];

    $('#table-of-contents').length > 0 ? $toc.appendTo('#table-of-contents') : $toc.prependTo('.article-body:first');

    // start with first H1

    function insertHeading(heading) {
    var $heading = $(heading);
    // what level heading are we on?
    var current_level = headingLevel(heading);

    // if it's an H1, add it to the original list
    if (current_level === 1) {
    newLi($heading, $firstUl);
    $currentUl = $firstUl;
    $arrayUl = [];

    // if it's the same as the one before it, add it to the current list
    else if (current_level === previous_level) {
    newLi($heading, $currentUl);

    // if it's one level higher than the one before it... time to make a new nested list
    else if (current_level > previous_level) {
    newLi($heading, $currentUl);

    else if (current_level<previous_level){
    for (i = 0; i < (previous_level-current_level); i++) {
    $currentUl = $arrayUl[$arrayUl.length-1];
    newLi($heading, $currentUl);

    previous_level = current_level;

    var $nextHeading = $heading.nextAll("h1, h2, h3, h4, h5, h6").first()[0];
    // if there's any headings left... run this again
    if ($nextHeading) insertHeading($nextHeading);

    // adds a new UL to the current UL
    function nestUl() {
    var $newUl = $('<ul>');
    $currentUl = $newUl;

    // returns a numerical value for each heading
    function headingLevel(heading) {
    switch (heading.nodeName) {
    case 'H1':
    return 1;
    case 'H2':
    return 2;
    case 'H3':
    return 3;
    case 'H4':
    return 4;
    case 'H5':
    return 5;
    case 'H6':
    return 6;
    return 0;

    // inserts a new line to the current list
    function newLi(heading, $list) {
    var $heading = $(heading);
    if ($heading.text().replace(/\s/g, '') == '') return null;
    var $wrapper = $('<li></li>');
    //var $link = $('<a>').prop('href', '#' + $heading.prop('id'));
    var $anchorname = $heading[0].innerText.replace (/\s/g,'');
    var $link = $('<a>').prop('href', '#' + $anchorname);



    var place_in_parent = $list.children('li').length;

    $heading.html("<a name=\"" + $anchorname + "\"></a>" + $link.find('.index').text() + ' ' + $heading.text());
  • Michael H
    Comment actions Permalink

    Am I missing something with implementing this code?

    Reading the thread, and taking the last post from @Tim, I understand the totality of the implementation path being this:

    1. In Guide, go to /theming/workbench
    2. Select your theme, and press view theme.
    3. press Edit code.
    4. Edit script.js, and add the code to the end of the file. Save changes.

    And that's it - it should display right?

    Having followed these steps on my Guide instance, running the Copenhagen theme, I don't get anything let alone the change i'm expected.

    Here's a page from my Guide instance which I would hope gets this auto TOC:

    Appreciate any help or feedback to understand where I'm going wrong.

  • Tim Capone
    Comment actions Permalink

    @Michael H


    You want to put it in the article_page.hbs file, not script.js

  • Paul LaBarbera
    Comment actions Permalink

    @Tim Capone

    Does it matter where in article-Page.hbs you put this script? I've tried adding this to a default Copenhagen theme, and I'm not seeing anything.


    I used Vladan's script and it worked fine. 

  • Tim Capone
    Comment actions Permalink

    @Paul LaBarbera

    I put my code on the bottom of the script.


    It's working on Firefox, Chrome, Internet Explorer, and Edge for me.

  • Stephen A Kairys
    Comment actions Permalink


    Per Tim's comment from last week:

    >> It's working on Firefox, Chrome, Internet Explorer, and Edge for me.

    Does anyone know if this code is browser-dependent? A former colleague who contributed to this thread (Nick Smolnehy) implemented this feature here. I believe he made some additions to the original code.

    Using Chrome, it's been working great, but I started using Firefos yesterday, and:

    1. The TOC itself does not display.
    2. The headings throughout the document are not auto-numbered  e.g

    2.1.3 Modify Vendor

    appears as

    Modify Vendor





  • Brett - Community Manager
    Comment actions Permalink

    Thanks for taking the time to share this with everyone Matthew!

  • Tyler Abate
    Comment actions Permalink

    Can a community team member assist me with adding a table of contents to my knowledge base? The above does not seem to work in 2020. Also, I am using H2 for my main headers.

  • Brett - Community Manager
    Comment actions Permalink

    Hey Tyler,

    This would require some custom code in your Guide theme which is not something we can help with from our end. I would recommend taking a look at the following documentation we have available:

    If you don't have the necessary resources available to assist with customizing your Help Center, we do have a Professional Services team that can assist at an additional cost. This is something you'll want to discuss with your account manager so if you're interested, I'm happy to get you in touch if needed.


  • Andrea Coloma
    Comment actions Permalink

    I added Lily Svetnik code and it worked but is there any way I can make this into side navigation and not the first thing on the article - does that make sense?


    Here is a link to an article:


Please sign in to leave a comment.

Powered by Zendesk