Automatic Table of Contents Generation

October 19th, 2008

Here’s a JavaScript snipplet for automatically generating a table of contents based on headings in a document. It will traverse all <h1>, <h2>, <h3>, etc. elements, add anchors (<a>) to them and generate nested unordered lists (<ul>, <li>) with links to the now anchored headings. The nesting honors the hierarchy of the headings.

For example, for a document that has the following headings:

<h1>Main Section 1</h1>
Some text

<h2>Sub-section</h2>
Some text

<h3>Sub-sub-section</h3>
Some text

<h1>Main Section 2</h1>

The generated HTML will be:

<ul>
    <li>
        Main Section 1
        <ul>
            <li>
                Sub-section
                <ul>
                    <li>Sub-sub-section</li>
                </ul>
            </li>
        </ul>
    </li>
    <li>
        Main Section 2
    </li>
</ul>

The code can be placed anywhere on an HTML page. It will locate all heading under the element with id “contents” and generate the table of contents inside the element with id “toc”:

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;
};

The HTML 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>

Take a peek at Automatic Table of Contents Demo to see this in action.

The code can be tweaked to remove the hard-coded dependency on the “contents” and “toc” elements. You could also add automatic section numbers (1, 1.2 etc.) to the table of contents as well as the original headings.

2 Comments

  1. cfq

    You could have generated a multi-level stack and later applied them to a template (which could also be passed as a parameter). Then it would have been a cleaner design for sure.

  2. brazzmonkey

    thank you for this script. one caveat, though: it won’t work for headings having a link between the “h” tags…

Add a Comment