All questions

Table of Contents

Premium

tableOfContents

A page's headings already describe its structure: an <h2> sits under the <h1> above it, an <h3> under that <h2>, and so on. Given a root element, walk its subtree in document order, find every heading (h1 through h6), and build a nested tree that mirrors that hierarchy — the same kind of outline a docs site renders in its sidebar.

Signature

type TocNode = { text: string; level: number; children: TocNode[] };

function tableOfContents(root: Element): TocNode[];

Each node carries the heading's text (its textContent), its level (the number in the tag: h2 is level 2), and a children array of headings that nest beneath it. The return value is an array of the top-level entries.

Examples

const root = document.createElement('div');
root.innerHTML = '<h1>Guide</h1><h2>Setup</h2><h2>Usage</h2>';

tableOfContents(root);
// → [
//     { text: 'Guide', level: 1, children: [
//         { text: 'Setup', level: 2, children: [] },
//         { text: 'Usage', level: 2, children: [] },
//       ] },
//   ]
root.innerHTML = '<h1>A</h1><h3>Deep</h3>';
tableOfContents(root);
// → [{ text: 'A', level: 1, children: [
//       { text: 'Deep', level: 3, children: [] },  // h3 nests under h1
//     ] }]

root.innerHTML = '<p>no headings here</p>';
tableOfContents(root);  // → []

Notes

  • Nest by level, not by DOM parent. A heading nests under the most recent heading with a smaller level, regardless of how the two sit in the DOM. Two headings in different sections can still be parent and child.
  • Document order. Headings come back in the order they appear in the document — a pre-order walk of the subtree. Headings nested inside divs or sections still count.
  • Level jumps are fine. An h1 followed directly by an h3 (no h2) nests the h3 under the h1. Do not invent a missing level.
  • Level rises pop back up. After an h3, an h2 is not a child of that h3 — it climbs back to attach under the nearest shallower heading.
  • A heading with no shallower ancestor is top-level. This includes an h2 that appears before any h1.
  • No headings returns an empty array. text is the full textContent, including the text of any inline markup.

Unlock the solution & editor

  • Runnable editor + tests

    Solve in the browser with instant Jest feedback.

  • Detailed solutions

    Walkthroughs, edge cases, and complexity notes.

  • Multi-framework variants

    React, Vue, Vanilla, Angular — same question, different stacks.

Upgrade to Premium