Product Decisions This Supports
- In-page navigation as a shippable feature, not a research spike. A nested TOC plus auto-injected anchor IDs is a ~half-day integration (Composer install + one service class + one Blade component) rather than a 1–2 sprint build. This is the kind of item that can move from "backlog nice-to-have" to "this sprint" once the buy cost is this low.
- Build vs. buy on a small, bounded problem. Hand-rolling heading extraction means handling level skipping (h2 → h4), nesting into
<ul> correctly, deduplicating IDs across a document, and tolerating both full documents and fragments. That's the classic "two days plus a quarter of edge-case bugs" trade. At MIT license and a tiny surface area, buying is clearly correct unless requirements diverge sharply.
- Unblocks content-heavy surfaces on the roadmap: help center / knowledge base articles, long-form blog posts, docs pages, legal and policy pages, and changelog entries. Anywhere a reader scrolls past one screen, this is a cheap comprehension and engagement win.
- Analytics and support-link hygiene. Auto-generated, unique anchor IDs mean deep links into specific sections become stable and shareable — useful for support macros ("see #refund-policy"), for anchor-level engagement tracking, and for reducing "scroll and find it" support tickets.
- Accessibility and SEO checkbox-filling. Semantic heading hierarchy exposed as navigable links supports screen-reader and keyboard users; anchor-addressable sections give search engines and in-SERP jump links something to target.
- A reversible decision. Because it's framework-agnostic and narrow, the cost of being wrong is one class and one Blade partial. This is safe to trial in a single content template before rolling it out globally — a genuinely low-risk A/B or staged-rollout candidate.
When to Consider This Package
Adopt when:
- Your content is server-rendered HTML — Blade templates, a CMS rendering to HTML, or markdown already converted upstream. This library parses HTML; it does not render markdown.
- You need TOC output on the backend (for SEO-crawlable markup, PDF/email generation, print stylesheets, or static export) rather than a client-side JS widget.
- Your requirements are conventional: nested lists, configurable heading-level bounds (e.g. only h2–h4), and auto-generated IDs. Nothing exotic.
- The team is Laravel/PHP and you want zero new infrastructure, zero JS bundle weight, and zero external service.
- You're comfortable with a small, single-maintainer, ~88-star package — and can accept that risk because the code surface is small enough to fork or vendor in an afternoon.
Look elsewhere when:
- You need markdown → HTML → TOC in one pass. Pair this with
league/commonmark or pick a renderer that emits a TOC itself; don't expect this to do both.
- You need custom slug rules (localized headings, non-ASCII transliteration, "pretty" permalinks matching existing URLs). ID generation here is about uniqueness, not editorial control — verify before you promise stable URLs, because changing IDs later breaks links.
- Your content is client-rendered (JS/SPA, live editor preview) — a JS-side TOC is a better fit.
- You need sanitization, not just parsing. This extracts and rewrites headings; it is not an HTML sanitizer. If headings come from untrusted users, you still need a sanitizer in front of it.
- You need sticky/scroll-spy TOC UI behavior — that's frontend work regardless; this only gives you the markup and the anchors.
- You need enterprise support, SLAs, or a security-review paper trail. There is none here.
Watch items for the decision log: no formal support channel, low adoption signal, and a single maintainer. Mitigate by pinning the version, wrapping it behind your own TableOfContentsService interface, and keeping a fork path documented.
How to Pitch It (Stakeholders)
One-liner: A small, free (MIT) PHP library that turns the headings already in our HTML into a nested, linkable table of contents — so long pages become navigable without a frontend project or a new service.
For executives: This is a low-cost, low-risk feature enabler. It lets us ship in-page navigation on our content pages — help articles, blog posts, policies — inside a single sprint, using existing PHP. No new vendor, no new infrastructure, no licensing cost, and it's small enough to replace if it doesn't work out. The expected return is better content engagement, more shareable deep links, and fewer "where do I find this" support tickets.
For engineering: One Composer dependency, framework-agnostic, MIT. Feed it an HTML string; get back a nested <ul> and HTML with unique IDs injected into each heading. Configurable min/max heading levels, works on full documents or fragments. We'll wrap it in a thin service and expose it as a Blade component so the dependency stays swappable. Known boundaries: it parses HTML but doesn't render markdown and doesn't sanitize — we keep commonmark and our sanitizer where they already are. Main risk is maintenance: small project, one maintainer — pin the version and keep the wrapper thin.
Ask: Approve a one-sprint spike-to-ship on a single content template, with a go/no-go review after we see real page behavior and analytics.