Automatic Table of Contents using jquery?
Any long page of content with distinct and well marked up content can benefit from a table to contents. A table of contents provides a quick way to jump down the page to the desired section. Of course you can create a table of contents manually, but it may be smart to build it dynamically on-the-fly with JavaScript. This is true for several reasons:
- It’s easier – write the JavaScript once and it can create the Table on Contents on every page you need it.
- It’s more reliable – the JavaScript isn’t subject to authoring errors.
- It’s still accessible – A table of contents is good for the general concept of accessibility, but it is a bonus (not having it doesn’t ruin the page) and nearly all screen readers run JavaScript.
This kind of thing has been done many times and many ways. But this time is ours! Plus it makes for a good tutorial.
HTML: Headers and IDs
A long page of different parts you wish to link to could be marked up a bunch of ways. Perhaps a FAQ page could be a <dl>
. It could literally be <section>
after <section>
. In our case, we’ll assume this structure:
<article>
<h3 id="question-one">Title of Question</h3>
<!-- whatever other content, probably some paragraphs and stuff. -->
<h3 id="question-two">Another Question</h3>
<!-- whatever other content, probably some paragraphs and stuff. -->
<!-- etc -->
</article>
A perfectly legit page full of headers with IDs and the content between them. Note the ID’s. They are unique, as any good ID ought to be. This is required because it gives us a link target.
A link like this:
<a href="#question-one">Link to Question One</a>
Will jump down the page when clicked until the element with the ID “question-one” is in view.
Building the Table of Contents with jQuery
Our goal is to inject HTML on the page in the form of a table of contents. Like this:
<nav role="navigation" class="table-of-contents">
<h2>On this page:</h2>
<ul>
<li><a href="#question-one">Question One</a></li>
</ul>
</nav>
A list in that <nav>
? Yep.
Step 1: A string of HTML
We’ll build this entirely dynamically. Perhaps it would be smart to use some kind of JavaScript templating for this. But hey, this is so simple, let’s just build a big string and append that.
var ToC =
"<nav role='navigation' class='table-of-contents'>" +
"<h2>On this page:</h2>" +
"<ul>";
We’re leaving several tags open there, we’ll close them before we are done.
Step 2: Loop through the headers
The <h3>
‘s on our page indicate each section we wish to link to, so we’ll find them all with a jQuery selector, then loop through each of them.
$("article h3").each(function() {
// loop
});
Step 3: Get the bits of data we need
We need 1) the text of each header, which we will turn into a link and 2) the ID of each header which we can turn into a href
attribute for that link.
var el, title, link;
$("article h3").each(function() {
el = $(this);
title = el.text();
link = "#" + el.attr("id");
});
Inside of that loop, “this” refers to the header element currently targeted, so to speak. we set “el” to a jQuery version of it, so we can use jQuery methods on it to extract that text and ID.
Step 4: Create a new list item and append to string
var newLine, el, title, link;
$("article h3").each(function() {
el = $(this);
title = el.text();
link = "#" + el.attr("id");
newLine =
"<li>" +
"<a href='" + link + "'>" +
title +
"</a>" +
"</li>";
ToC += newLine;
});
The “+=” there means “append this new string to the already existing string stored in this variable.
Step 5: Close the “template”
ToC +=
"</ul>" +
"</nav>";
Step 6: Inject HTML onto page
Now you’ll need to decide just exactly where you want this newly formed table to contents to be injected onto the page. Putting at the top of the page is probably smart.
Our example uses <article>
to wrap everything, so to inject at the top of that, we would do:
$("article").prepend(ToC);
In “real life”, perhaps you’d target a header and use insertAfter or another of jQuery’s fancy DOM insertion methods.