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

Twig Inspector Bundle Laravel Package

nowo-tech/twig-inspector-bundle

Twig Inspector Bundle adds a debugging toolbar to Symfony apps that reveals which Twig template rendered each part of a page. Hover over HTML elements to see template names, blocks, and file paths, making it easier to locate and fix view code during development.

View on GitHub
Deep Wiki
Context7

Getting Started

Install it as a development-only dependency:

composer require --dev nowo-tech/twig-inspector-bundle

Register the bundle manually (Symfony Flex may not have a recipe for a package this small) in config/bundles.php:

return [
    // ...
    Nowo\TwigInspectorBundle\TwigInspectorBundle::class => ['dev' => true],
];

The ['dev' => true] part matters: this bundle annotates rendered HTML so you can hover an element and see which Twig template and which {% block %} produced it. It must never be enabled on a production kernel.

Where to look first, in order:

  1. README.md in the repo — it is the only reliable source for the actual config key prefix and the toolbar toggle (shortcut/button). Do not assume the prefix matches the bundle name.
  2. src/DependencyInjection/Configuration.php — confirms the real config root node and every available option. Read this before writing any YAML.
  3. src/Resources/views/ — the toolbar/overlay template; this is where you go if the widget renders but looks broken.
  4. bin/console debug:container --tag=twig.extension and bin/console debug:twig — confirm the Twig extension and any exposed functions/filters actually registered.

First use case: you are handed a screenshot of a page region and need the file. Open any dev page in the browser, activate the inspector, click the region, and read back the template path plus block name. That single loop — "element on screen → file on disk" — is the entire value proposition; everything else is polish.

Implementation Patterns

The click-to-locate loop. Treat it as your first move during any template refactor or bug triage. Before grepping for a CSS class or a translation key, click the element and let the inspector name the template. Then open that file directly. This is meaningfully faster than grep -r "some-copy-string" templates/ when copy comes from translations or is assembled from several partials.

Refactor / dead-code sweeps. When consolidating partials, walk the page with the inspector open and note which includes are actually reachable. Blocks that the inspector never reports are candidates for deletion. Confirm with bin/console debug:twig and a fresh cache clear before deleting — an inspector miss is not proof of unreachability.

Design-handoff mapping. For each region in a design, record template:block in the ticket. This makes review conversations concrete ("the hero is _hero.html.twig block content") and gives the next developer a starting point without running the app themselves.

Keeping it out of the way. Wire the bundle env-gated (['dev' => true]), and add a project-local config file so options live in version control rather than in someone's head:

# config/packages/dev/twig_inspector.yaml
# verify the root key against src/DependencyInjection/Configuration.php
twig_inspector:
    enabled: true

If the bundle supports exclusions (paths, blocks, or templates), use them to silence vendor bundles and admin themes — otherwise the overlay gets noisy on every page and people stop using it.

Front-end toolchains. The bundle only touches server-rendered HTML, so it is orthogonal to Vite/Webpack asset pipelines. It works, as long as the markup it annotates survives to the DOM. If a JS framework hydrates or replaces a subtree, the annotations vanish with it. Use the inspector on the server-rendered response (view source, or disable hydration temporarily), not on the hydrated result.

Extending it. Because this is a small single-maintainer package, prefer decorating its services over patching vendor code. Concretely: decorate whatever service produces the annotation attributes if you need a custom naming scheme, and keep any project-specific overrides under src/Twig/ with a compiler pass in src/DependencyInjection/. That way a composer update cannot silently revert your work.

Team onboarding. Put one line in the project README: "install dev deps, run the app, click the toolbar icon, hover anything." This package's whole learning curve is that sentence, and nobody will discover it on their own.

Gotchas and Tips

  • Environment leakage is the top risk. A dev-only bundle registered for all envs will inject annotation attributes into production HTML: it bloats responses, leaks absolute template paths, and can break layout. Verify with APP_ENV=prod bin/console debug:container | grep -i inspector — it should return nothing.
  • Attribute injection can break markup. Adding data-* attributes is usually safe, but inside <table>, <select>, <svg>, or <pre> it can produce invalid nesting or visible whitespace. If a layout shifts only when the inspector is active, that is the cause, not your CSS.
  • Snapshot and E2E tests will diff. Any test asserting on raw HTML or full-page screenshots fails the moment annotations appear. Either disable the bundle in the test env (recommended) or strip the attributes in the test client's response before asserting.
  • Twig cache hides config changes. After editing config or overriding a template, run bin/console cache:clear (and restart the dev server if you use one). A "the inspector doesn't see my new block" report is almost always a stale cache.
  • Loops and embeds produce duplicates. A block rendered inside a {% for %} appears many times; the overlay may show the last or first instance depending on implementation. Do not read ordinal position as meaningful — read the template and block name only.
  • Inheritance is ambiguous. For an overridden block, it is not always obvious whether the inspector reports the parent file or the child. Cross-check with bin/console debug:twig <template> and {% dump %} / dump() if you need certainty. When in doubt, put a temporary unique string in the candidate block and search the page source.
  • Toolbar CSS collisions. The overlay typically uses a high z-index and its own font stack; app-level global styles (* { font-family: ... }, aggressive z-index stacking contexts, or overflow: hidden on body) can hide or misplace it. If the icon does not appear, check the console and the computed styles before assuming the bundle is broken.
  • Partial/HTMX/Turbo swaps. The toolbar initialises on page load. Content swapped in afterwards keeps its annotations (they are server-rendered) but the toolbar JS may not re-bind. A hard reload is the reliable fix; do not file this as a bug.
  • Pin the version. One star and a single maintainer means the API surface can move. Commit the composer.lock, and if you depend on a config key or an extension point in CI, add a smoke test that boots the kernel in dev and asserts the container still has the expected service. That converts a silent breakage into a red build.
  • require-dev discipline. Keep it out of require. If a downstream consumer ever installs your project with --no-dev, the bundle must simply not exist, and nothing in config/ may reference its services unconditionally.
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