MD073 - Table of Contents Validation¶
Overview¶
Rule ID: MD073 Alias: toc-validation Category: Other Fixable: Yes (marker-based TOCs only)
This rule validates that Table of Contents (TOC) sections match the actual document headings. It detects missing entries, stale entries, and text mismatches.
Configuration¶
[MD073]
# Enable the rule (opt-in, disabled by default)
enabled = true
# Minimum heading level to include (default: 2)
min-level = 2
# Maximum heading level to include (default: 4)
max-level = 4
# Whether TOC order must match document order (default: true)
enforce-order = true
# Spaces per indentation level (default: from MD007, or 2)
# indent = 4
Configuration Options¶
| Option | Type | Default | Description |
|---|---|---|---|
enabled |
boolean | false |
Whether to enable this rule (opt-in) |
min-level |
integer | 2 |
Minimum heading level to include in TOC |
max-level |
integer | 4 |
Maximum heading level to include in TOC |
enforce-order |
boolean | true |
Whether TOC entry order must match heading order |
indent |
integer | MD007's indent, or 2 |
Spaces per indentation level for nested TOC entries |
Indentation Configuration¶
By default, MD073 reads the indent value from MD007 to ensure TOC indentation matches your list indentation style. This means if you configure:
Then MD073 will automatically use 4-space indentation for nested TOC entries:
<!-- toc -->
- [Installation](#installation)
- [npm](#npm)
- [yarn](#yarn)
- [Usage](#usage)
<!-- tocstop -->
You can override this by setting indent explicitly in MD073:
TOC Detection Methods¶
Marker-Based Detection (Recommended)¶
Use HTML comments to mark the TOC region explicitly:
Alternative stop marker: <!-- /toc -->
Marker detection is case-insensitive and allows whitespace variations:
- <!-- toc -->
- <!--toc-->
- <!-- TOC -->
Auto-fix only works for marker-based TOCs because markers provide clear, unambiguous boundaries.
Heading-Based Detection¶
Detects TOC by looking for headings like "Table of Contents", "Contents", or "TOC":
The TOC region ends at the next heading or after two consecutive blank lines.
Note: Auto-fix is disabled for heading-based TOCs because the boundaries are fuzzy and could lead to unintended changes.
What This Rule Checks¶
Missing Entries¶
Headings that exist in the document but don't have corresponding TOC entries:
<!-- toc -->
- [Installation](#installation)
<!-- tocstop -->
## Installation
Content.
## Usage <-- Missing from TOC!
More content.
Stale Entries¶
TOC entries for headings that no longer exist:
<!-- toc -->
- [Installation](#installation)
- [Deleted Section](#deleted-section) <-- Heading doesn't exist!
<!-- tocstop -->
## Installation
Content.
Text Mismatches¶
TOC entry text differs from the actual heading:
<!-- toc -->
- [Install](#installation) <-- Should be "Installation"
<!-- tocstop -->
## Installation
Content.
Order Mismatches (when enforce-order = true)¶
TOC entries in wrong order compared to document headings:
<!-- toc -->
- [Usage](#usage) <-- Should come after Installation
- [Installation](#installation)
<!-- tocstop -->
## Installation
...
## Usage
...
Auto-Fix Behavior¶
When auto-fix is enabled, this rule:
- Only fixes marker-based TOCs - heading-based TOCs are not auto-fixed
- Generates a new TOC from all headings after the TOC region
- Respects
min-levelandmax-levelfilters - Uses GitHub-style anchors for link generation
- Uses nested indentation based on heading level
- Preserves markers (
<!-- toc -->...<!-- tocstop -->)
The fix is idempotent - running it multiple times produces the same output.
Examples¶
Correct TOC with Markers¶
# My Project
<!-- toc -->
- [Installation](#installation)
- [npm](#npm)
- [yarn](#yarn)
- [Usage](#usage)
<!-- tocstop -->
## Installation
### npm
npm install my-project
### yarn
yarn add my-project
## Usage
import MyProject from 'my-project';
Correct TOC with Heading¶
# My Project
## Contents
- [Installation](#installation)
- [Usage](#usage)
## Installation
...
## Usage
...
Rationale¶
Table of Contents sections are valuable for navigation in documentation, but they easily drift out of sync with actual headings when documents are refactored. This rule:
- Catches missing TOC entries when new sections are added
- Identifies stale entries when sections are removed or renamed
- Ensures TOC accurately reflects document structure
- Provides auto-fix to regenerate correct TOC
Special Cases¶
Headings in Code Blocks¶
Headings inside fenced code blocks are ignored:
## Real Heading <-- Included in TOC
\`\`\`markdown
## Example Heading <-- Ignored (in code block)
\`\`\`
Headings with Code Spans¶
Headings containing code spans work correctly:
Generates anchor: #check-paths
Duplicate Headings¶
Duplicate headings get numbered anchors:
Custom Anchors¶
Custom IDs using {#custom-id} syntax are respected:
Generates anchor: #my-custom-anchor instead of #my-section