A reusable Table of Contents package for Statamic that extracts headings from HTML, Markdown, and Bard content, generates stable anchors, and optionally injects heading IDs into rendered HTML.
- PHP 8.3+
- Laravel 12
- Statamic 6
composer require bit-mx/statamic-tocphp artisan vendor:publish --tag=statamic-toc-configThis publishes config/statamic-toc.php.
return [
'min_level' => 1,
'max_level' => 6,
'preserve_existing_ids' => true,
'default_source' => 'html',
'default_tree' => true,
'cache' => [
'enabled' => false,
'ttl' => 600,
'store' => null,
'prefix' => 'statamic_toc',
],
];min_level,max_level: Heading level range included in TOC.preserve_existing_ids: Keep existing heading IDs when injecting anchors.cache.enabled: Enable caching for tag output.cache.ttl: Cache lifetime in seconds.
This package is compatible with Statamic Blade tag usage like:
<s:toc :content="$content" :is_flat="false" depth="3" from="h1">
@isset($toc_id)
<a href="#{{ $toc_id }}">{{ $toc_title }}</a>
@if($has_children)
@foreach($children as $child)
<a href="#{{ $child['toc_id'] }}">{{ $child['toc_title'] }}</a>
@endforeach
@endif
@endisset
</s:toc>Supported legacy params:
contentfield(default:article)depth(default:3)from(default:h1)is_flat(default:false)
Legacy output keys are provided for drop-in compatibility:
toc_titletoc_idtoc_levelchildrenhas_childrentotal_childrentotal_resultsno_results
Use the toc tag to extract TOC items.
{{ toc:items source="html" :content="content" min_level="2" max_level="4" }}
<li><a href="#{{ id }}">{{ text }}</a></li>
{{ /toc:items }}Parameters:
source:html,markdown, orbard.content: The input payload to parse.min_level/max_level: Optional level limits.tree:true/falseto return hierarchical or flat output.
Inject heading IDs into rendered HTML:
{{ content | toc }}Optional params:
{{ content | toc:2:4:true }}Meaning:
- min level
- max level
- preserve existing IDs
use BitMx\StatamicToc\Facades\Toc;
$items = Toc::extractAsArray('markdown', $markdown, 1, 6, true);Or via DI:
use BitMx\StatamicToc\Toc\TocService;
public function show(TocService $tocService): array
{
return $tocService->extractAsArray('html', $html, 2, 4, true);
}Each item includes:
textlevelidurl(for example,#installation)children(whentree=true)
The Bard extractor walks nested node structures and set values, so headings inside nested/complex Bard content are included.
When cache.enabled=true, tag results are cached using a key that includes source, content, level range, and tree mode.
If you already have custom parser/tag/modifier classes in your project:
- Install this package.
- Replace custom TOC tag calls with package tag usage.
- Replace custom heading-id injection with
| tocmodifier. - Keep your front-end template markup, only swap data source.
- Remove legacy TOC classes after parity verification.
- Ensure content passed to modifier is rendered HTML.
- Confirm heading levels are within configured min/max.
- Duplicate heading text is expected to produce suffixes (
-2,-3, ...).
- Verify the field content passed to source
bardis raw Bard data (array structure).
- Disable cache during development.
- Check cache store and TTL settings.
composer testMIT