A Dynamic Table of Contents Script

by Matt Whitlock

^^ This table of contents right here ^^ isn't actually in the document source. See for yourself.

Introduction

For long, heavily-edited HTML documents, it becomes a major nuisance to keep a table of contents up to date. Perhaps even more annoying is keeping all of the section numbers contiguous and increasing. I offer a JavaScript solution here that dynamically builds a table of contents from the headings in a document and prepends legal-style section numbers to each of the headings.

Files

The effect of the script is evident on this page. You can examine the HTML for this page using the View Source command in your web browser. You should also look at the JavaScript code.

Compatibility

The script adheres to the W3C JavaScript DOM specification, but of course that says very little in the world of non-compliant browsers. I have tested the script and verified that it works in Internet Explorer 6 on Windows and in Mozilla Firefox 1.5 on Linux. Support for other browsers is untested. The script should degrade adequately on non-supporting browsers: it would probably produce a JavaScript error, but the page itself would not be left unusable.

Usage

Setting Up the Page

All you need to do to write a page that uses this script is to include the JavaScript code and add a call to generateTOC in your body's onload event handler:

<head>
<script src="toc.js" type="text/javascript"></script>
</head>

<body onload="generateTOC(document.getElementById('toc'));">

The document.getElementById('toc') tells the generateTOC function where you want it to insert the table of contents. The referenced element can be anything that can contain a <ul>.

<div id="toc"></div>

This page uses a stylesheet to suppress the list markers that would normally adorn the list items.

div#toc ul {
  list-style-type: none;
}

Adding Sections

Adding sections to your page could not be easier. Simply use a heading element. The text of your heading will automatically be captured and used by the script in generating the table of contents. Note that the script only processes heading levels 2 through 4 (<h2>, <h3>, <h4>); heading level 1 is reserved for the page title, and heading levels 5 and 6 are considered too insignificant to merit inclusion in the table of contents.

Important: You must not skip heading levels in the natural containment hierarchy, or the script will break. For example, you may not follow an <h2> with an <h4> without an intervening <h3>. However, it is permissible to follow an <h4> with an <h2> without an intervening <h3>.

How It Works

The generateTOC function is actually quite simple once you get over all the DOM syntax. Pseudocode is presented here to demonstrate the algorithm:

initialize the three level counters to zero
add a new <ul> element to the given element
for each element that is a direct child of the document body, do begin
if the element is an <h4>, then begin
increment the level 4 counter
if this is the first level 4 heading in the current level 3 section
append a new <ul> element to the last item in the current level 3 list
construct the section number from the level 2, level 3, and level 4 counters
prepend the section number to the heading element's text
set the id of the heading to the section number
append to the current level 4 list a new <li> element containing a link to the heading
else, if the element is an <h3>, then begin
increment the level 3 counter and zero the level 4 counter
if this is the first level 3 heading in the current level 2 section
append a new <ul> element to the last item in the current level 2 list
construct the section number from the level 2 and level 3 counters
prepend the section number to the heading element's text
set the id of the heading to the section number
append to the current level 3 list a new <li> element containing a link to the heading
else, if the element is an <h2>, then begin
increment the level 2 counter and zero the level 3 and level 4 counters
construct the section number from the level 2 counter
prepend the section number to the heading element's text
set the id of the heading to the section number
append to the table of contents a new <li> element containing a link to the heading
end if
end for
Valid XHTML 1.1