A long guide with six sections and no landmarks forces readers to scroll and guess where they are. The on-page table of contents gives every doc page a scan-friendly map of what is on this page, without leaving the article.
docs.page renders an On this page sidebar in the right column of each documentation page. It lists Markdown headings from the current page, links to in-page anchors, and highlights the section you are reading as you scroll.
The list is built at bundle time from your MDX source. You do not enable the table of contents per page or add a component to each file. It appears automatically on every doc page when the layout has room for it.
Which heading levels qualify is controlled globally through the content object in docs.json. The key that matters for the table of contents is content.headerDepth. That setting sits alongside other content defaults such as image zoom and previous/next link inference.
On wide viewports, the table of contents sits in a sticky column to the right of the article body. Each entry is a link to a heading anchor (#section-slug). As you scroll, the active entry updates so readers always know which section is in view.
Deeper headings are indented in the list so nested structure is visible at a glance. On narrower screens the column is hidden so the main content keeps full width. The heading anchors still work when readers follow deep links.
The table of contents reads Markdown heading lines from the page source: ## through ######. Headings inside fenced code blocks are ignored.
| Rule | Behavior |
|---|---|
| Minimum depth | h2 (##); fixed |
| Maximum depth | content.headerDepth (default 3, so h3) |
| Page title | Excluded. The visible title comes from frontmatter title, not a body # heading |
<Heading> components | Not extracted. Use Markdown syntax when you want a section in the table of contents |
Each included heading gets a slugified id for anchor links. Duplicate titles on the same page receive numeric suffixes (-1, -2, and so on).
See Heading for slug rules, anchor behavior, and when to use the <Heading> component instead of Markdown.
Set headerDepth under the content key in docs.json to control the deepest heading level that appears in the table of contents on every page:
{
"content": {
"headerDepth": 3
}
}The default is 3, which includes h2 and h3 sections. Increase the value to surface deeper structure, for example, 4 adds h4 headings, 5 adds h5, and 6 adds h6.
At build time, docs.page passes content.headerDepth to the MDX bundler as the maximum table-of-contents depth. Every page on the site uses the same limit; there is no per-page override.
If headerDepth is lower than the minimum depth (2) or invalid, no headings qualify and the On this page list is empty.
Structure long pages with ## for major sections and ### for subsections readers should be able to jump to. Avoid repeating the frontmatter title as # Page title in the body. That creates a duplicate heading and does not belong in the table of contents.
When a page has many small h4 or h5 headings, raising headerDepth can make the sidebar noisy. Start with the default and increase it only when deeper levels represent real navigation landmarks, not one-line labels.
