Search code examples
javascripttableofcontentshtml-heading

Is there a JavaScript solution to generating a "table of contents" for a page?


I have headers in <h1> through <h6> tags. Is there a way that I can use JavaScript to generate a table of contents for the contents that serves as anchor tags as well?

I would like the output to be something like:

<ol>
    <li>Header 1</li>
    <li>Header 1</li>
        <li>Header 2</li>
            <li>Header 3</li>
</ol>

I am not currently using a JavaScript framework, but I don't see why I couldn't use one.

I am also looking for something done, since I'm guessing this is a common problem, but if not, a starting point to roll my own would be good.


Solution

  • I couldn't resist putting together a quick implementation.

    Add the following script anywhere on your page:

    window.onload = function () {
        var toc = "";
        var level = 0;
    
        document.getElementById("contents").innerHTML =
            document.getElementById("contents").innerHTML.replace(
                /<h([\d])>([^<]+)<\/h([\d])>/gi,
                function (str, openLevel, titleText, closeLevel) {
                    if (openLevel != closeLevel) {
                        return str;
                    }
    
                    if (openLevel > level) {
                        toc += (new Array(openLevel - level + 1)).join("<ul>");
                    } else if (openLevel < level) {
                        toc += (new Array(level - openLevel + 1)).join("</ul>");
                    }
    
                    level = parseInt(openLevel);
    
                    var anchor = titleText.replace(/ /g, "_");
                    toc += "<li><a href=\"#" + anchor + "\">" + titleText
                        + "</a></li>";
    
                    return "<h" + openLevel + "><a name=\"" + anchor + "\">"
                        + titleText + "</a></h" + closeLevel + ">";
                }
            );
    
        if (level) {
            toc += (new Array(level + 1)).join("</ul>");
        }
    
        document.getElementById("toc").innerHTML += toc;
    };
    

    Your page should be structured something like this:

    <body>
        <div id="toc">
            <h3>Table of Contents</h3>
        </div>
        <hr/>
        <div id="contents">
            <h1>Fruits</h1>
            <h2>Red Fruits</h2>
            <h3>Apple</h3>
            <h3>Raspberry</h3>
            <h2>Orange Fruits</h2>
            <h3>Orange</h3>
            <h3>Tangerine</h3>
            <h1>Vegetables</h1>
            <h2>Vegetables Which Are Actually Fruits</h2>
            <h3>Tomato</h3>
            <h3>Eggplant</h3>
        </div>
    </body>
    

    You can see it in action at https://codepen.io/scheinercc/pen/KEowRK (old link: http://magnetiq.com/exports/toc.htm (Works in IE, FF, Safari, Opera))