Table of Contents Extension
TableOfContentsExtension automatically inserts a table of contents into your document with links to the various headings.
The Heading Permalink extension must also be included for this to work.
This extension is bundled with
league/commonmark. This library can be installed via Composer:
composer require league/commonmark
See the installation section for more details.
Environment as usual and simply add the
HeadingPermalinkExtension provided by this package:
use League\CommonMark\Environment\Environment; use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension; use League\CommonMark\Extension\HeadingPermalink\HeadingPermalinkExtension; use League\CommonMark\Extension\TableOfContents\TableOfContentsExtension; use League\CommonMark\MarkdownConverter; // Define your configuration, if needed // Extension defaults are shown below // If you're happy with the defaults, feel free to remove them from this array $config = [ 'table_of_contents' => [ 'html_class' => 'table-of-contents', 'position' => 'top', 'style' => 'bullet', 'min_heading_level' => 1, 'max_heading_level' => 6, 'normalize' => 'relative', 'placeholder' => null, ], ]; // Configure the Environment with all the CommonMark parsers/renderers $environment = new Environment($config); $environment->addExtension(new CommonMarkCoreExtension()); // Add the two extensions $environment->addExtension(new HeadingPermalinkExtension()); $environment->addExtension(new TableOfContentsExtension()); // Instantiate the converter engine and start converting some Markdown! $converter = new MarkdownConverter($environment); echo $converter->convertToHtml('# Awesome!');
This extension can be configured by providing a
table_of_contents array with several nested configuration options. The defaults are shown in the code example above.
The value of this nested configuration option should be a
string that you want set as the
class attribute. This defaults to
This should be a
string that defines one of three different strategies to use when generating a (potentially-nested) list from your various headings:
See “Normalization Strategies” below for more information.
string controls where in the document your table of contents will be placed. There are two options:
'top'(default) - Insert at the very top of the document, before any content
'before-headings'- Insert just before the very first heading - useful if you want to have some descriptive text show above the table of content.
'placeholder'- Location is manually defined by a user-provided placeholder somewhere in the document (see the
If you’d like to customize this further, you can implement a custom event listener to locate the
TableOfContents node and reposition it somewhere else in the document prior to rendering.
When combined with
'position' => 'placeholder', this setting tells the extension which placeholder content should be replaced with the Table of Contents. For example, if you set this option to
[TOC], then any lines in your document consisting of that
[TOC] placeholder will be replaced by the Table of Contents. Note that this option has no default value - you must provide this string yourself.
string option controls what style of HTML list should be used to render the table of contents:
'bullet'(default) - Unordered, bulleted list (
'ordered'- Ordered list (
These two settings control which headings should appear in the list. By default, all 6 levels (
6). You can override this by setting the
max_heading_level to a different number (
Consider this sample Markdown input:
## Level 2 Heading This is a sample document that starts with a level 2 heading #### Level 4 Heading Notice how we went from a level 2 heading to a level 4 heading! ### Level 3 Heading And now we have a level 3 heading here.
Here’s how the different normalization strategies would handle this input:
All links in your table of contents will be shown in a flat, single-level list:
<ul class="table-of-contents"> <li> <p><a href="#level-2-heading">Level 2 Heading</a></p> </li> <li> <p><a href="#level-4-heading">Level 4 Heading</a></p> </li> <li> <p><a href="#level-3-heading">Level 3 Heading</a></p> </li> </ul> <!-- The rest of the content would go here -->
Level 1 headings (
<h1>) will appear on the first level of the list, with level 2 headings (
<h2>) nested under those, and so forth - exactly as they occur within the document. But this can get weird if your document doesn’t start with level 1 headings, or it doesn’t properly nest the levels:
<ul class="table-of-contents"> <li> <ul> <li> <p><a href="#level-2-heading">Level 2 Heading</a></p> <ul> <li> <ul> <li> <p><a href="#level-4-heading">Level 4 Heading</a></p> </li> </ul> </li> <li> <p><a href="#level-3-heading">Level 3 Heading</a></p> </li> </ul> </li> </ul> </li> </ul> <!-- The rest of the content would go here -->
Applies nesting, but handles edge cases (like incorrect nesting levels) as you’d expect:
<ul class="table-of-contents"> <li> <p><a href="#level-2-heading">Level 2 Heading</a></p> <ul> <li> <p><a href="#level-4-heading">Level 4 Heading</a></p> </li> </ul> <ul> <li> <p><a href="#level-3-heading">Level 3 Heading</a></p> </li> </ul> </li> </ul> <!-- The rest of the content would go here -->