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 id attribute of the nested a tag, used for fragment-link href values
  • 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 li element containing an a with href="#{id}" linking to the heading's anchor
  • When children exist, an inner ol element 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 TocReader class in src/lib/contentUtils/tocReader.js.
  • The parser uses regular expressions to extract h2 through h4 headings with anchor IDs, then recursively nests them into a hierarchical tree.
  • The TocReader.readToC method returns a table-of-contents custom element containing nested ordered lists, or undefined if no headings exist.
  • The snippet worker in src/lib/contentUtils/modelWorkers/snippet.js integrates this logic, respecting the tocEnabled front-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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →