Table of contents
TableOfContentsExtension replaces an explicit marker with a document outline
and assigns stable IDs to root headings. Each marker may select its own heading
range and list style.
Install
This extension is bundled with alto/markdown.
composer require alto/markdownConfigure
<?php
use Alto\Markdown\Extension\TableOfContents\TableOfContentsExtension;
use Alto\Markdown\Markdown;
$markdown = Markdown::commonmark()->with(new TableOfContentsExtension());Markdown
# Guide
@toc {min: 2}
## Intro *now*
### Use [`it`](https://example.com)HTML
<h1 id="guide">Guide</h1>
<nav class="table-of-contents" id="toc">
<ul>
<li><a href="#intro-now">Intro now</a>
<ul>
<li><a href="#use-it">Use it</a></li>
</ul>
</li>
</ul>
</nav>
<h2 id="intro-now">Intro <em>now</em></h2>
<h3 id="use-it">Use <a href="https://example.com"><code>it</code></a></h3>
Options
Configure document-wide defaults with TableOfContentsPolicy:
<?php
use Alto\Markdown\Extension\TableOfContents\TableOfContentsPolicy;
use Alto\Markdown\Extension\TableOfContents\TableOfContentsStyle;
$extension = new TableOfContentsExtension(new TableOfContentsPolicy(
minLevel: 2,
maxLevel: 4,
style: TableOfContentsStyle::Ordered,
htmlClass: 'contents',
id: 'contents',
title: 'On this page',
marker: '[[toc]]',
));| Option | Default |
|---|---|
minLevel, maxLevel |
1, 6 |
style |
TableOfContentsStyle::Bullet |
htmlClass |
table-of-contents |
id |
toc |
title |
null |
marker |
@toc |
A marker may override three values locally:
@toc {min: 2, max: 3, ordered: true}Levels must be between 1 and 6. ordered accepts only true or false.
htmlClass is limited to 256 bytes without control characters. id is
limited to 128 bytes without whitespace or control characters. A title is
limited to 512 bytes without unsupported control characters. Custom markers
contain 1 to 64 visible ASCII bytes and cannot contain braces.
Security
Titles, classes, IDs, heading text, and link fragments are escaped through the active HTML output context. Malformed directives remain literal Markdown and do not partially apply options.
Behavior
Only root headings appear in the outline. Headings inside block quotes, lists, and extension containers still receive stable IDs but are excluded from the catalog. Multiple markers share one catalog and receive unique navigation IDs. If no heading matches a marker, the marker renders no HTML. The source marker is preserved when rendering back to Markdown.