Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Toc Laravel Package

caseyamcl/toc

caseyamcl/toc is a PHP library that generates a nested table of contents from HTML headings. It parses h1–h6 elements, adds anchor IDs, and outputs a customizable, hierarchical TOC list for documentation and long-form pages.

Deep Wiki
Context7

Technical Evaluation

Architecture fit

  • Narrow, single-responsibility utility: HTML in → nested <ul> TOC (and optionally heading anchors) out. It is a rendering concern, not a domain concern, so it belongs in the presentation layer (a Blade component, a view helper, or a small TocBuilder service), never in models or controllers directly.
  • Framework-agnostic and PSR-4/Composer-native, which means it will not conflict with Laravel's container or package discovery — but it also gives you nothing for free (no service provider, no config file, no facade). Treat it as a library you wrap, not a package you install.
  • Natural home in our stack: long-form content surfaces — CMS article bodies, help-center/docs pages, policy pages, email-to-HTML pipelines — anywhere we render WYSIWYG or Markdown-derived HTML and want in-page navigation plus deep-linkable headings.

Integration feasibility

  • Very high. composer require caseyamcl/toc, wrap in a ~40-line adapter, expose as a Blade component. No DB, no queue, no external service, no credentials. An engineer can spike this against real content in under a day.
  • The only hard platform dependency is PHP's DOM extension (ext-dom/libxml), which is present in essentially every standard Laravel runtime image; confirm it is enabled in our production and CI images rather than assuming.
  • Confirm the actual Composer dependency tree before committing — if it pulls a DOM-crawler or HTML5 parser, that is a second transitive surface to track; if it is ext-dom only, the audit story is trivial.

Technical risk

  • HTML parsing fidelity (primary risk). DOMDocument::loadHTML is HTML4-era and lossy: it can reorder/normalize markup on re-serialization, mishandle HTML5 elements (<section>, <figure>, custom elements), and mangle UTF-8 unless the document declares a charset or is pre-encoded. Since this library mutates headings and returns the document, the risk is not just a wrong TOC — it is silently corrupted article HTML.
  • Sanitization ordering. If we render user-authored HTML, anchor injection requires DOM round-tripping. Decide explicitly: sanitize → then TOC (safe, but TOC may reference IDs a sanitizer stripped) or TOC → sanitize (anchor IDs may be dropped). Neither is free; this is a policy decision, not a code decision.
  • Heading-level quality. Real content authoring is sloppy (h1 → h3 jumps, multiple h1s, headings used for styling). Output nesting will mirror that sloppiness. Low technical risk, high cosmetic/support risk.
  • Adoption signal. 88 stars and a single-maintainer profile means bus factor ~1. Mitigated by the small surface area: worst case we fork a ~1k-line library. Acceptable for a presentation-layer utility; not acceptable for anything with security or data-integrity ownership.
  • Anchor collisions. Auto-generated IDs must be checked against pre-existing id attributes and deduplicated, otherwise deep links break or point at the wrong section.

Key questions

  1. Does the API return a modified HTML string, a DOMDocument, and/or a structured array of headings — and can we hand it a document we already parsed, to avoid parsing twice?
  2. How are pre-existing id attributes on headings handled — preserved, overwritten, or deduplicated against generated ones?
  3. What is the UTF-8/multibyte behavior for non-Latin headings, and what slugging algorithm (if any) generates IDs?
  4. Is the returned HTML re-serialized in a way that changes our stored/rendered markup (whitespace, void elements, HTML5 tags)?
  5. What PHP versions are supported, and does it depend on ext-dom only?
  6. Is there a documented behavior for zero headings, a single heading, or skipped levels — and does it fail soft?

Integration Approach

Stack fit

  • Laravel 10/11/12 on PHP 8.1+ is a clean fit: Composer-native, no framework coupling, no global state.
  • Recommended shape: a TocService (or TocBuilder) in app/Support that takes a raw HTML string plus options (minLevel, maxLevel, anchorPrefix), returns a DTO { tocHtml, contentHtml }. A <x-toc> Blade component and a @toc directive sit on top. This keeps the third-party namespace out of views and gives us one seam to swap or fork later.
  • Cache the DTO keyed on sha1(contentHtml + options) in the response/view cache; article bodies are static per revision, so hit rates should be excellent.

Migration path

  • Greenfield surfaces (new docs/help-center pages) first — zero legacy markup to defend.
  • Existing CMS article bodies second: run a one-off backfill script that renders N sample articles through the adapter and diffs before/after HTML to quantify re-serialization damage. Gate rollout on that diff being empty or trivially cosmetic.
  • No data migration required — this is compute-on-read. That is the main reason the change is low-risk to schedule.

Compatibility

  • Watch three things: PHP version floor, ext-dom in prod/CI images, and interaction with our existing HTML sanitizer (mews/purifier or HTMLPurifier) and Markdown renderer (commonmark). Define a single canonical pipeline order and enforce it in one place.
  • If any surface uses client-side TOC generation today, keep the server-rendered TOC as the source of truth to avoid duplicate/conflicting anchors.

Sequencing

  1. Spike: adapter + 20 representative real documents (malformed markup included), diff output, confirm UTF-8 and HTML5 handling.
  2. Decide sanitizer ordering and write it down as a documented invariant.
  3. Ship adapter + Blade component + feature tests (no headings, nested headings, skipped levels, duplicate IDs, non-ASCII).
  4. Add caching and a metrics counter (TOC generated / cache hit).
  5. Roll out to one surface behind a config flag; expand after a week of clean logs.

Operational Impact

Maintenance

  • Low ongoing cost: no config, no migrations, no background jobs. The liability is version bumps — pin the minor version and review changelogs, since a 2025-12 active release cadence means the API surface may still move.
  • Because it is framework-agnostic, Laravel upgrades will not break it, but PHP upgrades (and eventual native HTML5 Dom\HTMLDocument support in PHP 8.4+) may make it redundant. Note it as a candidate for replacement in ~18–24 months.

Support

  • Single maintainer, low star count, no Laravel-specific docs. Internal support burden is ours. Budget for the adapter being the documented, tested seam, and be prepared to vendor/fork if upstream stalls.
  • User-facing support load comes from content quality, not the library: authors will ask why the TOC skips a level or why a heading has no anchor. Put authoring guidance (use sequential heading levels) in the CMS docs.

Scaling

  • Generation is CPU-bound DOM parsing, roughly linear in document size — fine for typical article bodies (tens of KB), questionable for very large pages (100KB+ single documents) under high read volume.
  • Mitigation is caching, not horizontal scaling. Per-revision cache keys make invalidation trivial. For high-traffic pages, precompute at publish time (write the TOC into a column or cache entry) rather than at request time.
  • No memory or connection-pool concerns; each call is self-contained.

Failure modes

  • Empty TOC — content with no headings, or all headings outside the configured level range. UI must degrade gracefully (render nothing, not an empty <ul>).
  • Malformed/garbled content — DOM re-serialization alters stored markup; the page still renders but may look subtly wrong. Detected only by diff testing.
  • Broken anchors — duplicate or stale IDs, or IDs stripped by the sanitizer, producing dead deep links. Highest-severity user-visible failure; test explicitly.
  • Encoding corruption — mojibake in headings for non-Latin content if charset handling is not pinned.
  • Exception on invalid input — wrap the call in a try/catch that logs and falls back to rendering content without a TOC. A missing TOC is an acceptable degradation; a 500 on an article page is not.

Ramp-up

  • An afternoon for a mid-level engineer to integrate; roughly 2–3 days to do it properly with the diff harness, sanitizer-ordering decision, caching, and tests.
  • No new operational tooling, no on-call runbook changes beyond one log-based alert for adapter exceptions.
  • Recommendation: proceed. The blast radius is small, the integration cost is measured in days, and the value (deep-linkable headings, accessible in-page nav) is real. The conditions are: build the adapter seam, diff-test against real content before broad rollout, and pin the dependency.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
elmogy/larafast
xeviant/laravel-paystack
gorilladash/laravel-website-sdk
martialbe/flysystem-oss
chondal/3312client
jeroen-g/flickr
opscale-co/nova-genbi
itsjustvita/laravel-retention
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log
gregsphotography/site-builder-components
io-digital/clickatell
snowsoft/laravel-admin
oxygen/auth
relicsoftware/barakah-payment-gateway
tobya/work-with-composer
equipc/laravel-email-validator
equipc/laravel-email-database-log
adedsec/nova-translated-labels