enabel/layout-bundle
Deprecated Symfony bundle providing a responsive Bootstrap 5 layout with Enabel styling, Twig components (alerts, theme and locale switchers, user menu), favicon management, error and email templates, and light/dark mode theming.
Read the deprecation notice first. This bundle is no longer maintained and points to enabel/ux as its successor. Treat it as a fit only for existing Enabel-styled Symfony apps or short-lived internal projects; starting greenfield work on it means inheriting unpatched templates and a design system that will drift.
composer require enabel/layout-bundle
Enabel\LayoutBundle\EnabelLayoutBundle::class => ['all' => true] to config/bundles.php.php bin/console config:dump-reference enabel_layout
Copy only the keys you actually change into config/packages/enabel_layout.yaml — the defaults are the intended happy path.vendor/enabel/layout-bundle/templates/ (block names and component signatures are the real documentation), then docs/, then CHANGELOG.md for BC breaks around component parameters.First use case: render a page against the shipped base layout and drop in one component.
{# templates/home/index.html.twig #}
{% extends '@EnabelLayout/layout.html.twig' %}
{% block content %}
{% include '@EnabelLayout/components/alert.html.twig' with {
type: 'success',
message: 'Saved.'
} only %}
<h1>Dashboard</h1>
{% endblock %}
If that renders with Enabel styling, the bundle is wired correctly and everything else is composition.
Inherit, don't rebuild. The base layout gives you the navbar, theme handling, favicon and flash-message region. Extend it and override narrow blocks rather than copying the file — the moment you copy, you own the whole template and lose the point of the dependency.
{% extends '@EnabelLayout/layout.html.twig' %}
{% block title %}{{ parent() }} — Invoices{% endblock %}
{% block content %} ... {% endblock %}
Flash messages: map your keys once. The alert component takes a single type/message pair, so loop your flashes through it in one shared partial (templates/_flashes.html.twig) and include that from the base override. Keep the mapping in that one file — Symfony's error typically needs normalizing to Bootstrap's danger, and duplicating that logic across pages is how inconsistent UI creeps in.
Navbar composition. Theme switcher, locale switcher and user menu are designed to sit together in the navbar. Render them once in a navbar block override so every page inherits the same behaviour:
{% block navbar_tools %}
{% include '@EnabelLayout/components/theme_switcher.html.twig' %}
{% if app.request.locale is defined %}
{% include '@EnabelLayout/components/locale_switcher.html.twig' with {
locales: ['en', 'fr', 'nl']
} only %}
{% endif %}
{% include '@EnabelLayout/components/user_menu.html.twig' with {
user: app.user,
actions: [
{ label: 'Profile', route: 'app_profile' },
{ label: 'Logout', route: 'app_logout' }
]
} only %}
{% endblock %}
Server-render the theme class. The switcher persists the choice client-side, but the initial page load must already carry the right attribute on <html> or you get a flash of the wrong theme. Read the stored value in a small Twig extension or a request listener and expose it as a global; do not rely on JS to apply it after paint.
Override bundle templates the Symfony way. Error pages and email templates are the highest-value overrides:
templates/bundles/EnabelLayoutBundle/Exception/error404.html.twig
The directory segment must match the bundle name exactly (EnabelLayoutBundle), and the path must mirror the vendor path — a typo silently falls through to the vendor file, which is the usual cause of "my override isn't picked up."
Emails are a separate concern. Reuse the mail layout for branding consistency, but inline the CSS (or run through a CSS inliner) and test in a real client. A layout tuned for a browser and Bootstrap's flexbox will degrade in Outlook; keep email overrides deliberately dumb.
Adopt incrementally. For a legacy app, you can pull in only the components (@include the alert or switcher partials) without extending the base layout at all. That keeps blast radius small and makes the eventual migration to enabel/ux a matter of swapping includes.
composer.json ("enabel/layout-bundle": "x.y.*"), and record the migration to enabel/ux as a tracked issue the day you install it.assets/ directory and own them. Extending via selectors against a dead package is a slow-motion breakage.data-bs-theme="dark" on <html>; older Enabel builds toggle a .dark class. If components look half-themed, this is almost always why — check both the layout template and the switcher's JS before debugging your own CSS.framework.translator.enabled_locales (or the locales passed to the component) is empty, the component renders nothing or lists every locale. Verify the switcher's translation domain is loaded too, or labels show as raw keys.bin/console debug:twig @EnabelLayout # confirm the namespace and see template paths
bin/console debug:config enabel_layout # confirm what config actually resolved to
bin/console lint:twig templates vendor/enabel/layout-bundle/templates
bin/console cache:clear # template/config changes are cached in prod
services.yaml, (4) patch the vendor directory — never. Anything beyond (2) is a migration liability.aria-* states before shipping to a public audience.How can I help you explore Laravel packages today?