HTML Table of Contents Generator

Last updated: April 12, 2022.

Manually making a table of contents for your article or blog can be a lot of work!

Thankfully, you can automate this process using JavaScript.

The table of contents generator below creates a ToC for HTML content structured with heading elements (e.g. h2, h3, h4 etc.).

All you need to manually specify is:

  • The HTML element on your page in which the headings are contained
  • The depth of the ToC (e.g. until h4)

Table of contents generator function

Here is the script you need to add to your website or blog to start using the table of contents generator.

If you are using WordPress, place this code between <script></script> tags in the footer section:

/* Place ToC generator function in page footer */

function makeToC(article, depth) {
    /* Necessary arguments: (element to make ToC for, heading depth) /*

    /* Determine ToC depth by selecting elements based upon user input */
    let search;
    if (depth === 'h2') {
        search = 'h2';
    } if (depth === 'h2') {
        search = 'h2';
    } else if (depth === 'h3') {
        search = 'h2, h3';
    } else if (depth === 'h4') {
        search = 'h2, h3, h4';
    } else if (depth === 'h5') {
        search = 'h2, h3, h4, h5';
    } else if (depth === 'h6') {
        search = 'h2, h3, h4, h5, h6';
    } else {
        throw new Error("Non-valid depth argument. Examples: 'h2', 'h4'");
    }

    const headings = article.querySelectorAll(search);
    const toc = document.createElement('ul');


    /* Cycle through each heading, conditionally appending to ToC */
    for (i=0; i<headings.length; i++) {

        /* H2 is a simple case: always appended to ToC */
        if (headings[i].tagName === 'H2') {
            
            const li = document.createElement('li');
            li.textContent = headings[i].textContent;
            toc.append(li);

        }

        /* For H2, H3, H4, H5 and H6 */
        if (headings[i].tagName === 'H3' || headings[i].tagName === 'H4' ||
            headings[i].tagName === 'H5' || headings[i].tagName === 'H6') {
            
            /* If one heading deeper (than previous), create new ul with li inside */
            const previousHeading = headings[i-1];

            if (headings[i].tagName !== previousHeading.tagName) {
                const newUl = document.createElement('ul'); 
                const li = document.createElement('li');
                li.textContent = headings[i].textContent;
                newUl.append(li);
                if (headings[i].tagName === 'H3') {
                    toc.append(newUl); // If H3, append ul directly to ToC
                } else if (headings[i].tagName === 'H4') {
                    toc.lastChild.append(newUl); // H4 +1 deeper
                } else if (headings[i].tagName === 'H5') {
                    toc.lastChild.lastChild.append(newUl);  // H5 +2 deeper
                } else if (headings[i].tagName === 'H6') {
                    toc.lastChild.lastChild.lastChild.append(newUl); // H6 +3 deeper
                }
            /* If heading the same as the previous one, create an li and append */
            } else {
                const li = document.createElement('li');
                li.textContent = headings[i].textContent;
                if (headings[i].tagName === 'H3') { // If H3, append li in last child
                    toc.lastChild.append(li);
                } else if (headings[i].tagName === 'H4') { // H4 +1 deeper
                    toc.lastChild.lastChild.append(li);
                } else if (headings[i].tagName === 'H5') { // H5 +1 deeper
                    toc.lastChild.lastChild.lastChild.append(li);
                } else if (headings[i].tagName === 'H6') { // H6 +1 deeper
                    toc.lastChild.lastChild.lastChild.lastChild.append(li);
                }
            }
        }
    }
    // Inserts ToC where script tag is placed on page
    currentScript.parentElement.insertBefore(toc, currentScript)
}

Usage

After adding this, place the script below in the place on your page where you would like the table of contents to appear.

But before doing so, you should check the settings.

First, you may need to change document.querySelector('.the-content') to point at the HTML element in which your heading elements are contained. If you are using WordPress, you do not need to change anything, as it is already set the point to the container of a WordPress post or page.

Second, you may want to change the depth of the table of contents by changing h4 in makeToC(myArticle, 'h4'). This is set to generate a table of contents including h2, h3 and h4 headings. A greater heading number will increase the depth of the table of contents, and a lower one will increase it.

<!-- Place this script where ToC should appear -->

<script>
const currentScript = document.currentScript;
window.addEventListener("load", () => {
    const myArticle = document.querySelector('.the-content'); // Sets document for making ToC to WordPress default for a page/post
    makeToC(myArticle, 'h4'); // 'h4' sets depth of ToC
})
</script>

Summary

With a little JavaScript, the process of creating a HTML table of contents for your website or blog can be automated.

If you do use this in your project, consider letting us know by posting a link in the comments section below. We'd love to see it used to ease the load on busy writers and editors as much as possible!