Build a dynamic table of contents from article h2 tags

Basic DOM querying and dynamic element creation in vanilla JS.
Query h2s with querySelectorAll, assign ids, map to anchor links, append a nav list.
Importing jQuery or a framework for a six-line native task.
WHAT THIS TESTS: This question checks whether you understand the Document Object Model as a programming interface that represents the page as nodes and objects so programs can change document structure and content. The interviewer wants to see you use core DOM methods to query a live tree, create new elements, and mutate attributes without relying on external libraries. At the senior level it also reveals whether you think about scoping, accessibility, and progressive enhancement.
A GOOD ANSWER COVERS: A strong response follows four steps in order. First, scope the search by calling querySelectorAll on the article container rather than document, which prevents accidentally capturing h2 tags from the site header or footer. Second, iterate the resulting NodeList and ensure every heading has a unique id attribute; if an id is missing, generate a URL-friendly slug from the heading textContent and assign it. Third, construct the table of contents by creating a nav or ul element with document.createElement, then for each heading append an li containing an anchor whose href is a fragment pointing to that id. Fourth, inject the finished list into the DOM at the desired mount point, typically before the article body. Mentioning that querySelectorAll returns a static NodeList and that textContent avoids HTML parsing overhead shows depth.
COMMON WRONG ANSWERS: Red flags include suggesting jQuery or a framework for a task solvable in roughly ten lines of vanilla JavaScript. Another mistake is using innerHTML to assemble the list, which bypasses the DOM tree and risks XSS if heading text contains malicious markup. Failing to generate or validate ids means the anchor links will be broken. Some candidates query the entire document for h2 tags without scoping, which breaks when the page layout changes. A subtle error is using innerText instead of textContent, which introduces layout-dependent behavior that can fail in hidden or script-blocked contexts.
LIKELY FOLLOW-UPS: The interviewer may ask how you would handle duplicate heading text, which requires appending an index to keep ids unique. They might ask how to make the table of contents update if the article is edited dynamically, leading to a MutationObserver or a re-render function. Accessibility follow-ups include asking whether you would add aria-labelledby or a skip link, or how you would preserve focus management when a user activates a table-of-contents link. Performance questions could cover whether you would debounce the build step on resize or if you would offload this work to a web worker, though for typical article lengths that is usually unnecessary.
ONE CONCRETE EXAMPLE: Imagine an article container with the class content. You would write const headings = document.querySelectorAll(".content h2"); const toc = document.createElement("ul"); headings.forEach((h, i) => { if (!h.id) { const slug = h.textContent.toLowerCase().replace(/\s+/g, "-").replace(//g, "") || "heading"; h.id = slug + "-" + i; } const li = document.createElement("li"); const a = document.createElement("a"); a.href = "#" + h.id; a.textContent = h.textContent; li.appendChild(a); toc.appendChild(li); }); document.querySelector(".content").prepend(toc); This uses the DOM tree methods the HTML DOM API provides to read and write the document structure directly.
Read the original → developer.mozilla.org
Get five bites like this every day.
Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.