How 30 Seconds of Code Generates Table of Contents for Articles
The 30 Seconds of Code project automatically generates tables of contents by parsing rendered HTML with a custom TocReader class that extracts heading levels, nests them hierarchically, and converts them into semantic markup.
The 30 Seconds of Code repository is a popular collection of short JavaScript snippets and coding articles. To help readers navigate lengthy documentation, the project implements an automatic table of contents generation system that transforms markdown headings into interactive navigation trees without requiring authors to manually markup their content.
Parsing Headings from Rendered HTML
The TOC generation process operates on rendered HTML rather than raw markdown. In src/lib/contentUtils/tocReader.js, the TocReader class defines a regular expression matcher that identifies h2 through h4 elements containing an anchor tag with an id attribute.
The matcher extracts three critical pieces of data from each heading:
- Level: The heading rank (2, 3, or 4)
- Anchor ID: The
idattribute of the nestedatag, used for fragment-linkhrefvalues - Text: The plain text content of the heading
This extraction produces a flat array of heading objects that serve as the raw material for the hierarchical TOC structure.
Nesting Headings and Rendering the TOC Structure
Once the flat list is extracted, TocReader.nestHeadings recursively groups headings into a tree structure based on their levels. An h4 element becomes a child of the preceding h3, which itself nests under its parent h2.
The TocReader.toNavItem method transforms each node into HTML markup:
- An
lielement containing anawithhref="#{id}"linking to the heading's anchor - When children exist, an inner
olelement containing the nested sub-list
The public entry point TocReader.readToC orchestrates the entire process. It returns a string containing a custom table-of-contents element wrapping an ordered list, or undefined if no qualifying headings are found.
Integration with the Snippet Processing Pipeline
The TOC generation hooks into the content pipeline at src/lib/contentUtils/modelWorkers/snippet.js. After converting markdown to HTML, the worker checks the tocEnabled boolean flag (which defaults to true in front-matter) to determine whether to generate a TOC for that specific article.
The implementation passes the rendered fullDescriptionHtml to TocReader.readToC:
const tableOfContentsHtml = tocEnabled
? TocReader.readToC(fullDescriptionHtml) || ''
: '';
The resulting HTML string is stored in the tableOfContentsHtml field of the snippet model and later exported as the tableOfContents property available to templates.
Practical Code Examples
Using TocReader Directly
import TocReader from '#src/lib/contentUtils/tocReader.js';
// articleHtml is the rendered HTML content from markdown
const tocHtml = TocReader.readToC(articleHtml);
if (tocHtml) {
console.log('Generated TOC:', tocHtml);
} else {
console.log('No headings found – TOC not generated');
}
Integrating TOC Generation in a Content Worker
import TocReader from '#src/lib/contentUtils/tocReader.js';
import MarkdownParser from '#src/lib/contentUtils/markdownParser/markdownParser.js';
async function buildSnippet(snippet) {
const fullDescriptionHtml = await MarkdownParser.parse(
snippet.fullText,
snippet.language
);
const toc = snippet.tocEnabled
? TocReader.readToC(fullDescriptionHtml) || ''
: '';
return {
...snippet,
fullDescriptionHtml,
tableOfContentsHtml: toc,
};
}
Expected TOC Markup Output
<table-of-contents>
<ol>
<li><a href="#introduction">Introduction</a></li>
<li>
<a href="#usage">Usage</a>
<ol>
<li><a href="#basic-example">Basic Example</a></li>
<li><a href="#advanced-options">Advanced Options</a></li>
</ol>
</li>
<li><a href="#reference">Reference</a></li>
</ol>
</table-of-contents>
Summary
- The 30 Seconds of Code project generates TOCs from rendered HTML using the
TocReaderclass insrc/lib/contentUtils/tocReader.js. - The parser uses regular expressions to extract
h2throughh4headings with anchor IDs, then recursively nests them into a hierarchical tree. - The
TocReader.readToCmethod returns atable-of-contentscustom element containing nested ordered lists, orundefinedif no headings exist. - The snippet worker in
src/lib/contentUtils/modelWorkers/snippet.jsintegrates this logic, respecting thetocEnabledfront-matter flag to conditionally generate TOCs for each article.
Frequently Asked Questions
How does the TOC generator handle deeply nested headings?
The TocReader.nestHeadings method recursively groups headings based on their level, allowing h4 elements to nest under h3 headings, which themselves nest under h2 headings. The algorithm constructs a tree structure that preserves the document hierarchy regardless of nesting depth, though the parser specifically targets h2 through h4 elements and ignores h1 and deeper levels.
Can authors disable the table of contents for specific articles?
Yes, authors can control TOC generation through front-matter metadata. The snippet processor checks the tocEnabled boolean flag (which defaults to true) in each article's front-matter. When set to false, the TocReader.readToC method is skipped and an empty string is assigned to the tableOfContentsHtml field, effectively disabling the TOC for that specific snippet.
Why does the TOC generator parse HTML instead of Markdown?
The generator operates on rendered HTML because the 30 Seconds of Code pipeline converts Markdown to HTML early in the processing chain. Parsing HTML allows the TocReader to work with normalized, rendered content where heading anchors have already been generated, ensuring that the TOC links match the actual DOM structure. This approach also handles any Markdown extensions or plugins that might modify heading output during the HTML conversion phase.
What HTML structure does the generated TOC produce?
The TocReader.readToC method returns a string containing a custom table-of-contents element wrapping a nested ol structure. Each heading becomes an li containing an a with href linking to the heading's anchor ID. When headings have child elements, the method generates nested ol lists inside the parent li, creating a hierarchical navigation tree that reflects the document structure.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →