PHPackages                             caseyamcl/toc - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. caseyamcl/toc

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

caseyamcl/toc
=============

Simple Table-of-Contents Generator for PHP. Generates TOCs based off H1...H6 tags

v4.1.0(6mo ago)91368.9k↓41.1%155MITPHPPHP ^8.2CI failing

Since Feb 2Pushed 6mo ago1 watchersCompare

[ Source](https://github.com/caseyamcl/toc)[ Packagist](https://packagist.org/packages/caseyamcl/toc)[ Docs](https://github.com/caseyamcl/toc)[ RSS](/packages/caseyamcl-toc/feed)WikiDiscussions master Synced 2d ago

READMEChangelog (10)Dependencies (9)Versions (20)Used By (5)

PHP TOC Generator
=================

[](#php-toc-generator)

Generates a Table of Contents from *H1...H6* Tags in HTML Content

[![Latest Version on Packagist](https://camo.githubusercontent.com/aae169a8d0c1470f8d874672e59935645463860fd3f157f0510bb52a12614266/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6361736579616d636c2f746f632e737667)](https://packagist.org/packages/caseyamcl/toc)[![Software License](https://camo.githubusercontent.com/074b89bca64d3edc93a1db6c7e3b1636b874540ba91d66367c0e5e354c56d0ea/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d627269676874677265656e2e737667)](LICENSE.md)[![Github Build](https://github.com/caseyamcl/toc/workflows/Github%20Build/badge.svg)](https://github.com/caseyamcl/toc/actions?query=workflow%3A%22Github+Build%22)[![Code coverage](https://github.com/caseyamcl/toc/raw/master/coverage.svg)](coverage.svg)[![PHPStan Level 8](https://camo.githubusercontent.com/0729e562e10fac943b16dbb271b4af26488f779a33fc82cc3eef1e37a432c0b4/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048505374616e2d6c6576656c253230352d627269676874677265656e2e737667)](https://phpstan.org/)[![Total Downloads](https://camo.githubusercontent.com/b488899b1ff7021d43871fcb6b6b07ac542ed517fe9f7a1e5281a311bc0cb0c9/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f6361736579616d636c2f746f632e737667)](https://packagist.org/packages/caseyamcl/toc)

**NOTE: Version 4 of this library requires PHP 8.2 or newer.**

- Version 3 is no longer maintained, but it supports PHP 7.2 - 8.1: `composer require caseyamcl/toc ^3.0`
- Version 2 is no longer maintained, but it supports PHP5 - 7.1: `composer require caseyamcl/toc ^2.0`

This package provides a simple, framework-agnostic library to build a Table-of-Contents from HTML markup. It does so by evaluating your *H1...H6* tags. It can also automatically add appropriate *id* anchor attributes to header tags so that in-page links work.

Features:

- Generates HTML menus and [KnpMenu Item](https://github.com/KnpLabs/KnpMenu) menus
- Adds anchor ID attributes to *H1*...*H6* tags in your content where they do not already exist
- You can specify which *H1*...*H6* heading tag levels to include in the TOC
- Includes a Twig extension for generating TOCs and compatible markup directly in your templates
- Uses the flexible [KnpMenu Library](https://github.com/KnpLabs/KnpMenu) to generate menus
- [PSR-12](https://www.php-fig.org/psr/psr-12/) compliant
- Unit-tested (95% coverage) and PHPStan Level 7 tested

In the spirit of [KISS philosophy](https://en.wikipedia.org/wiki/KISS_principle), this library makes a few assumptions:

1. The hierarchy of your content is defined solely by the header (*H1*...*H6*) tags. All other tags are ignored when generating the TOC.
2. The link titles in the Table of Contents match either the `title` attribute of the header tag, or if there is no `title`, the (slugged) plaintext body of the header tag.

Installation Options
--------------------

[](#installation-options)

Install via [Composer](https://getcomposer.org/) by including the following in your `composer.json` file:

```
composer require caseyamcl/toc ^4.0

```

Or, drop the `src` folder into your application and use a [PSR-4 autoloader](https://www.php-fig.org/psr/psr-4/) to include the files.

Usage
-----

[](#usage)

This package contains two main classes:

1. `TOC\MarkupFixer`: Adds `id` anchor attributes to any *H1*...*H6* tags that do not already have any (you can specify which header tag levels to use at runtime)
2. `TOC\TocGenerator`: Generates a Table of Contents from HTML markup

Basic Example:

```
$myHtmlContent = fix($myHtmlContent) . "";

// This generates the Table of Contents in HTML
$htmlOut .= "" . $tocGenerator->getHtmlMenu($htmlOut) . "";

echo $htmlOut;
```

This produces the following output:

```

    This is a header tag with no anchor id
    Lorum ipsum doler sit amet
    This is a header tag with an anchor id
    Stuff here
    This is a header tag with an anchor id

                    This is a header tag with an anchor id

                            This is a header tag with an anchor id

```

Twig Integration
----------------

[](#twig-integration)

This library includes a [Twig](https://twig.symfony.com/) extension that enables you to load TOC lists and add anchors to markup from your Twig templates.

To enable Twig integration, [register the `TocTwigExtension`](https://twig.symfony.com/doc/3.x/api.html#using-extensions)with your Twig environment:

```
use Twig\Environment;
use Twig\Loader\FilesystemLoader;

$myTwig = new Environment(new FilesystemLoader());
$myTwig->addExtension(new TOC\TocTwigExtension());
```

The extension adds a Twig function for generating an HTML Table of Contents:

```
{# Generates HTML markup for given htmlContent #}
{{ toc(htmlContent) }}
```

It also provides a function and a filter for ensuring that your content includes anchors for all HTML header tags.
They both do the same thing, so choose which one suits your needs best:

```
{# Adds anchor links (id tags) for given htmlContent #}
{{ add_anchors(htmlContent) }}

{# You can also use it as a filter #}

    {{ htmlContent | add_anchors }}

```

Your HTML content may be hard-coded in your Twig Template. An easy way to accommodate this is to make sure the content is surrounded by `{% block %}...{% endblock %}` tags, and then just pass in that block to the *toc* function.

For example:

```
{% extends 'base.html.twig' %}
{% block page_content %}

   {{ toc(add_anchors(block('my_writeup'))) }}

   {{ add_anchors(block('my_writeup')) }}

{% endblock %}

{% block my_writeup %}
Hi There
Lorum ipsum baz biz etecetra
This is some content
More content here.  Blah blah
{% endblock %}
```

Specifying Heading Levels to Include
------------------------------------

[](#specifying-heading-levels-to-include)

You can choose to include only specific *h1...h6* heading levels in your TOC. To do this, pass two additional arguments to the `TocGenerator::getHtmlMenu()` method: `$topLevel` and `$depth`. For example:

```
$tocGenerator = new TOC\TocGenerator();
$someHtmlContent = 'TestLorum ipsumTest2Lorum ipsum';

// Get TOC using h2, h3, h4
$tocGenerator->getHtmlMenu($someHtmlContent, 2, 3);

// Get TOC using h1, h2
$tocGenerator->getHtmlMenu($someHtmlContent, 1, 2);

// Get TOC using h4, h5, h6
$tocGenerator->getHtmlMenu($someHtmlContent, 4, 3);
```

Most other methods in the package handle these arguments as well:

```
$tocGenerator = new TOC\TocGenerator();
$markupFixer = new TOC\MarkupFixer();
$someHtmlContent = 'TestLorum ipsumTest2Lorum ipsum';

// Get KnpMenu using h1, h2, h3
$tocGenerator->getMenu($someHtmlContent, 1, 3);

// Fix markup for h3, h4 tags only
$markupFixer->fix($someHtmlContent, 3, 2);
```

Twig functions and filters accept these arguments as well:

```
{# Generate TOC using h2, h3 tags #}
{{ toc(my_content, 2, 3) }}

{# Add anchors to h4, h5, h6 tags #}
{{ my_content | add_anchors(4, 3) }}
```

Customizing Menu Output
-----------------------

[](#customizing-menu-output)

You can customize the rendering of lists that the `TocGenerator` class outputs. By default, `TocGenerator` uses the [KnpMenu ListRenderer](https://github.com/KnpLabs/KnpMenu/blob/master/src/Knp/Menu/Renderer/ListRenderer.php) class to output the HTML.

You can pass your own instance of the `ListRenderer` class to `TocGenerator::getHtmlMenu()`. Or you can pass in your own renderer (implements [`Knp\Menu\Renderer\RendererInterface`](https://github.com/KnpLabs/KnpMenu/blob/master/src/Knp/Menu/Renderer/RendererInterface.php)).

For example, you may wish to use different CSS classes for your list items:

```
$someHtmlContent = 'TestLorum ipsumTest2Lorum ipsum';

$options = [
    'currentAsLink' => false,
    'currentClass'  => 'curr_page',
    'ancestorClass' => 'curr_ancestor',
    'branch_class'  => 'branch'
];

$renderer = new Knp\Menu\Renderer\ListRenderer(new Knp\Menu\Matcher\Matcher(), $options);

// Render the list
$tocGenerator = new TOC\TocGenerator();
$listHtml = $tocGenerator->getHtmlMenu($someHtmlContent, 1, 6, $renderer);
```

### Customizing with Twig

[](#customizing-with-twig)

The KnpMenu library offers more robust integration with the [Twig Templating System](https://twig.symfony.com/)than is offered by default with this library. You can take advantage of it by using the [TwigRenderer](https://github.com/KnpLabs/KnpMenu/blob/master/doc/02-Twig-Integration.markdown#using-the-twigrenderer)that is bundled with KnpMenu:

```
use Knp\Menu\Matcher\Matcher;
use Knp\Menu\Renderer\TwigRenderer;
use Twig\Environment;
use Twig\Loader\FilesystemLoader;

$someHtmlContent = 'TestLorum ipsumTest2Lorum ipsum';

$twigLoader = new FilesystemLoader(array(
    __DIR__.'/vendor/KnpMenu/src/Knp/Menu/Resources/views',
    // ...paths to your own Twig templates that render KnpMenus...
));

$twig = new Environment($twigLoader);
$itemMatcher = new Matcher();
$menuRenderer = new TwigRenderer($twig, 'knp_menu.html.twig', $itemMatcher);

$tocGenerator = new TOC\TocGenerator();

// Output the Menu using the template
echo $menuRenderer->render($tocGenerator->getMenu($someHtmlContent));
```

Ordered vs Unordered Lists
--------------------------

[](#ordered-vs-unordered-lists)

The KnpMenu library produces unordered lists (`ul`) by default. This library includes a custom renderer for ordered lists:

```
$someHtmlContent = 'TestLorum ipsumTest2Lorum ipsum';

// Ordered List
$orderedRenderedList = (new TOC\TocGenerator())->getOrderedHtmlMenu($someHtmlContent);
```

Twig Usage:

```
{# Generate ordered TOC #}
{{ toc_ordered(my_content) }}

{# The same options can be used for ordered lists as unordered lists #}
{{ toc_ordered(my_content, 1, 3) }}
```

### Making ordered lists prettier using CSS

[](#making-ordered-lists-prettier-using-css)

Below is some CSS to make your ordered lists look extra fancy ([credit to](https://github.com/caseyamcl/toc/issues/18) @flaushi).

```
.toc ol {
  list-style-type: none;
  counter-reset: item;
  margin: 0;
  padding: 0;
}

.toc ol > li:before  {
  counter-increment: item;
  margin: 0;
  padding: 0;
  content: counters(item, ".") ". ";
```

Sample output:

```
1. Some heading
1.1 Some sub-heading
1.2 Another sub-heading
2. Another heading
2.0.1. Sub-sub-sub heading

```

###  Health Score

61

—

FairBetter than 98% of packages

Maintenance66

Regular maintenance activity

Popularity51

Moderate usage in the ecosystem

Community24

Small or concentrated contributor base

Maturity84

Battle-tested with a long release history

 Bus Factor1

Top contributor holds 96.1% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~233 days

Recently: every ~376 days

Total

18

Last Release

206d ago

Major Versions

v1.2 → v2.02018-11-09

v2.x-dev → v3.02020-08-20

v3.2.0 → v4.0.02024-12-20

PHP version history (5 changes)v1.0PHP &gt;=5.4

v2.1PHP ^7.1

v3.0.1PHP ^7.1|^8.0

v3.0.2PHP ^7.2|^8.0

v4.0.0PHP ^8.2

### Community

Maintainers

![](https://www.gravatar.com/avatar/8db51cd614310a5de4822be9602de578e6d6dd2af7949d52fcd375ba2a8d1c74?d=identicon)[caseyamcl](/maintainers/caseyamcl)

---

Top Contributors

[![caseyamcl](https://avatars.githubusercontent.com/u/53035?v=4)](https://github.com/caseyamcl "caseyamcl (148 commits)")[![Schlaefer](https://avatars.githubusercontent.com/u/143224?v=4)](https://github.com/Schlaefer "Schlaefer (2 commits)")[![ArdaGnsrn](https://avatars.githubusercontent.com/u/52893305?v=4)](https://github.com/ArdaGnsrn "ArdaGnsrn (1 commits)")[![NicoHood](https://avatars.githubusercontent.com/u/6888294?v=4)](https://github.com/NicoHood "NicoHood (1 commits)")[![peter279k](https://avatars.githubusercontent.com/u/9021747?v=4)](https://github.com/peter279k "peter279k (1 commits)")[![yaquawa](https://avatars.githubusercontent.com/u/13927101?v=4)](https://github.com/yaquawa "yaquawa (1 commits)")

---

Tags

TOCtable-of-contents

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StylePHP\_CodeSniffer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/caseyamcl-toc/health.svg)

```
[![Health](https://phpackages.com/badges/caseyamcl-toc/health.svg)](https://phpackages.com/packages/caseyamcl-toc)
```

###  Alternatives

[sylius/sylius

E-Commerce platform for PHP, based on Symfony framework.

8.5k5.9M737](/packages/sylius-sylius)[drupal/core-recommended

Locked core dependencies; require this project INSTEAD OF drupal/core.

6942.5M421](/packages/drupal-core-recommended)[oro/platform

Business Application Platform (BAP)

645143.5k115](/packages/oro-platform)[contao/core-bundle

Contao Open Source CMS

1231.6M2.8k](/packages/contao-core-bundle)[shopware/core

Shopware platform is the core for all Shopware ecommerce products.

585.6M574](/packages/shopware-core)[jolicode/castor

A lightweight and modern task runner. Automate everything. In PHP.

54743.1k4](/packages/jolicode-castor)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
