Markdown Table of Contents Generator

Paste a Markdown document and get a ready-to-use table of contents built from its headings, indented by level with GitHub-compatible anchor links. Choose how deep to go and whether the list is bulleted or numbered. Headings inside code fences are ignored, and everything is generated locally as you type.

How to use the Markdown Table of Contents Generator

Paste your document into the Markdown box. The tool scans for ATX headings — lines that begin with one to six # characters — and builds a nested list, updating live. Max depth controls the deepest level included, so you can keep the contents to top-level sections or drill down to sub-subsections. Style switches between dash bullets, asterisk bullets, and a numbered list, and Anchor links turns each entry into a clickable link that jumps to that heading on GitHub, GitLab, and most Markdown renderers.

Each link target is a slug generated the same way GitHub does it: the heading text is lowercased, punctuation is removed, and spaces become hyphens, so "FAQ & Troubleshooting" links to #faq--troubleshooting. When two headings produce the same slug, a numeric suffix is added to the later ones (-1, -2) to match the way renderers disambiguate duplicates. The Indent from first heading level option treats whatever your shallowest heading is as the top of the tree, which is useful when a document starts at H2 rather than H1.

Headings that appear inside fenced code blocks (between ``` lines) are ignored, since a # there is a comment or shell prompt, not a real heading. Press Copy TOC to grab the result and paste it near the top of your file. Everything runs in your browser, so your document is never uploaded.

Anchor slugs and why a TOC is fiddly by hand

A table of contents seems trivial — just list the headings — but doing it correctly by hand is more error-prone than it looks, and the reason is anchor slugs. When a Markdown renderer turns a heading into HTML, it also gives that heading an id attribute so it can be linked to directly. A table of contents is really a list of links to those ids, and if a single slug is wrong the link silently goes nowhere. The trouble is that the slug is not the heading text verbatim; it is a transformed version, and the transformation has specific rules that are easy to misremember.

The common GitHub-flavored algorithm lowercases the text, strips out characters that are not letters, numbers, spaces, or hyphens, and then replaces each run of spaces with a single hyphen. So "Getting Started" becomes getting-started, but a heading like "API & SDK Reference" becomes api--sdk-reference — note the doubled hyphen, because the ampersand is removed and the surrounding spaces both convert. Emoji and accented characters have their own handling, and crucially, duplicate headings must get distinct ids: if a document has two "Examples" headings, the first is examples and the second becomes examples-1. Reproducing all of this in your head while also tracking indentation is exactly the kind of repetitive, detail-sensitive task that a generator should own.

The other subtlety is structure. A good contents list mirrors the heading hierarchy with indentation, so an H3 nested under an H2 is indented one level deeper — but only relative to the levels actually present. A file whose headings run H1, H2, H3 should indent cleanly, yet a file that jumps from H1 straight to H3 should not leave a confusing empty level. There is also the matter of code fences: a line like # install dependencies inside a shell example is a comment, not a heading, and including it would pollute the contents with noise. Handling fenced blocks, depth limits, duplicate slugs, and consistent indentation together is what separates a usable table of contents from a list that looks right but links wrong. Generating it automatically means the contents stays correct even as you add, rename, and reorder sections — you regenerate instead of hand-editing anchors.

Common use cases

  • READMEs. Add a navigable contents list to a long project README or wiki page.
  • Docs. Keep a generated TOC in sync as you add and rename sections.
  • Long articles. Give blog posts or guides jump links to each section.
  • Anchor checking. See the exact GitHub-style slug each heading will get.

Frequently asked questions

How are the anchor links generated?

Using the GitHub-flavored rule: lowercase the heading, remove characters other than letters, numbers, spaces, and hyphens, then replace spaces with hyphens. Duplicate headings get a numeric suffix like -1.

Does it ignore headings inside code blocks?

Yes. Lines between triple-backtick fences are skipped, so a # used as a shell comment or in a code sample is not mistaken for a heading.

Can I limit how deep the contents go?

Yes, use Max depth to include only headings up to H1, H2, H3, and so on. Deeper headings are omitted from the list.

My document starts at H2 — will indentation look right?

Enable "Indent from first heading level" to treat the shallowest heading present as the top level, so the list is not indented by an extra empty step.