How to build a nested markdown table of contents
- Step 1Load the multi-level doc — Paste or upload a Markdown file that uses several heading levels (H1-H4 or deeper).
- Step 2Set the top level — minDepth determines the flush-left level. Keep 1 to include the H1, or set 2 to start the outline at H2.
- Step 3Cap the depth — Use maxDepth (1-6) to limit how deep the outline goes — for example maxDepth=3 to hide H4+ detail.
- Step 4Choose placement — position=after-h1 (default) drops the nested TOC under the title; position=top puts it above the body.
- Step 5Generate the outline — Run it; each heading is slugged and indented by two spaces per level of depth minus minDepth.
- Step 6Review and save — Confirm the indentation matches your intended hierarchy, then download the updated Markdown.
How indentation maps to heading depth
Indent = 2 spaces × (heading depth − minDepth). The examples assume minDepth=1.
| Heading | Depth | Indent (spaces) | TOC line |
|---|---|---|---|
| # Title | 1 | 0 | - [Title](#title) |
| ## Section | 2 | 2 | - [Section](#section) |
| ### Sub-section | 3 | 4 | - [Sub-section](#sub-section) |
| #### Detail | 4 | 6 | - [Detail](#detail) |
minDepth shifts the whole outline left
Indentation is relative to minDepth, so the top included level is always flush-left.
| Doc starts at | minDepth | Flush-left level | Next level indent |
|---|---|---|---|
| H1 | 1 | H1 (0 spaces) | H2 at 2 spaces |
| H2 | 2 | H2 (0 spaces) | H3 at 2 spaces |
| H2 | 1 | (no H1) H2 at 2 spaces | H3 at 4 spaces |
| H3 | 3 | H3 (0 spaces) | H4 at 2 spaces |
Depth and placement options
The complete option set — three controls, no presets or reorder.
| Option | Default | Range / values | Use for nesting |
|---|---|---|---|
| minDepth | 1 | 1-6 | Sets the flush-left top level of the outline. |
| maxDepth | 6 | 1-6 | Caps the deepest level shown; anything deeper is dropped. |
| position | after-h1 | after-h1, top | Where the nested TOC is inserted relative to the H1. |
Cookbook
Recipes show how depth settings change the shape of the outline. Watch the indentation — it is the whole point of a nested TOC.
Full hierarchy, H1 at the top (defaults)
minDepth=1, maxDepth=6 produces the complete outline with the H1 as the root.
INPUT
# Spec
## Scope
### In Scope
### Out of Scope
## Design
OUTPUT (TOC)
## Table of Contents
- [Spec](#spec)
- [Scope](#scope)
- [In Scope](#in-scope)
- [Out of Scope](#out-of-scope)
- [Design](#design)Section excerpt starting at H2 (minDepth=2)
When you paste a chapter that starts at H2, set minDepth=2 so the H2s become the flush-left level.
INPUT ## Authentication ### Tokens ### Sessions OUTPUT (TOC, minDepth=2) ## Table of Contents - [Authentication](#authentication) - [Tokens](#tokens) - [Sessions](#sessions)
Cap the outline at three levels (maxDepth=3)
Hide H4+ noise from a deeply nested spec while keeping the top three levels.
INPUT
# API
## Endpoints
### Users
#### Fields
##### Validation
OUTPUT (TOC, maxDepth=3)
- [API](#api)
- [Endpoints](#endpoints)
- [Users](#users)
# H4 'Fields' and H5 'Validation' are droppedSkipped heading levels indent to true depth
An H4 placed directly under an H2 still indents to depth 4 — the outline reflects raw depth, not sequence.
INPUT
## Setup
#### Advanced
OUTPUT (TOC)
- [Setup](#setup)
- [Advanced](#advanced)
# 'Advanced' indents 6 spaces (depth 4 - minDepth 1 = 3 levels)Nested TOC with minDepth=1 but no H1
If the doc has no H1, the top level (H2) indents one step in, reflecting its absolute depth.
INPUT
## Overview
### Details
OUTPUT (TOC, minDepth=1)
- (no H1 entry)
- [Overview](#overview)
- [Details](#details)Edge cases and what actually happens
Document jumps from H2 straight to H4
By designIndentation reflects absolute depth, so the H4 indents to its real level (deeper than the H2) even though the intermediate H3 is missing. The outline shows the true depth, not a renumbered sequence.
minDepth greater than the shallowest heading
FilteredHeadings shallower than minDepth are excluded entirely. Set minDepth=2 on a doc with an H1 and that H1 simply will not appear in the outline.
minDepth set above maxDepth
Empty rangeAn inverted range matches no levels, so no headings qualify and the document is returned unchanged.
Negative indentation guarded
ClampedIf a heading is shallower than minDepth would normally allow, the indent is clamped to zero (never negative). Filtering removes those headings first, so the outline stays well-formed.
Heading with inline code or bold
CleanedBackticks and emphasis markers are stripped from the link text, so ### \config.yaml\` becomes - config.yaml` — note punctuation is also removed from the anchor.
Two siblings with the same title
Duplicate anchorBoth nest at the correct depth but share one slug and link to the first. No -1/-2 is appended; differentiate the wording for unique anchors.
Headings inside a fenced block
SkippedCode-block lines are ignored, so a sample outline inside ``` does not corrupt your real nesting.
Document with a single heading
SupportedA one-heading doc produces a one-line TOC at the flush-left level. Nesting only appears once there are multiple levels.
Setext (underline) headings
Not detectedOnly ATX # headings are parsed, so Setext-style headings produce no TOC entries. Normalize them to # form first.
File over the free tier cap
RejectedFiles larger than 1 MB / 500,000 characters are rejected on free. Long specs may need Pro (10 MB / 5,000,000 characters).
Frequently asked questions
How is the nesting decided?
Each heading is indented by two spaces times depth - minDepth. With minDepth=1, H1 is flush-left, H2 indents once, H3 twice, and so on.
My section starts at H2 — how do I make it the top level?
Set minDepth=2. Indentation is relative to minDepth, so the H2s become flush-left and H3s nest beneath them.
What if I skip a heading level?
Indentation reflects absolute depth, so an H4 under an H2 indents to depth 4. The outline shows true depth rather than collapsing the gap.
Can I limit how deep the outline goes?
Yes — maxDepth (1-6) drops anything deeper. maxDepth=3 keeps a three-level outline and hides H4+ detail.
Does the nesting use tabs or spaces?
Two spaces per level. This renders consistently as a nested list in all major Markdown renderers.
Where is the nested TOC placed?
After the first H1 by default (position=after-h1), or at the top of the body with position=top. Frontmatter stays on top.
Are the anchors GitHub-compatible?
For ASCII headings, yes. Non-Latin characters are stripped from the slug, which differs from GitHub's Unicode handling.
Why do two same-named sub-sections share a link?
Identical text produces the same slug. The tool does not append -1/-2, so rename one for a unique anchor.
Will it nest headings inside code samples?
No. Anything inside a fenced ``` block is skipped, so sample outlines never pollute the real nesting.
Can I make a sidebar/sticky TOC?
No — this produces an inline Markdown list. Sidebar TOCs depend on your renderer (Docusaurus, MkDocs, etc.) and are configured there.
How big a document can it process?
Free tier: 1 MB / 500,000 characters. Pro: 10 MB / 5,000,000. Larger tiers go higher still.
What if my heading levels are inconsistent?
Normalize them with the Heading Shifter or tidy spacing with the Prettifier before generating, so the nesting reflects a clean tree.
Privacy first
All Markdown processing runs locally in your browser using JavaScript. No file is ever uploaded to JAD Apps servers — only metadata counters are saved for signed-in dashboard stats.