elnur/bootstrap-bundle
ElnurBootstrapBundle adds unobtrusive Bootstrap 3 support to Symfony forms, letting you choose default, horizontal, inline, or navbar layouts, set button contexts, use input group addons, convert labels to placeholders, and render flash messages.
First, the framework reality check. elnur/bootstrap-bundle is a Symfony 2 bundle, not a Laravel package. It hooks into the Symfony Form component's Twig theming layer and is registered through AppKernel::registerBundles(). It has no service provider, no facade, and no Blade integration. The string-type syntax in the README ($builder->add('submit', 'submit', ...)) was removed in Symfony 3, so this targets the Symfony 2.x era alongside Bootstrap 3 — both long past end-of-life.
So there are two honest paths:
composer require elnur/bootstrap-bundle:~0.1
Register new Elnur\Bundle\BootstrapBundle\ElnurBootstrapBundle() in AppKernel.php. Load Bootstrap 3 CSS/JS yourself — the bundle deliberately does not ship or inject assets.layout switch and a context option for buttons) and reimplement them as Blade components. That is the realistic day-to-day value of this package for you.Where to look first (read the source, not the README):
Resources/views/Form/*.html.twig — the actual theme blocks. This is the whole product.DependencyInjection/Configuration.php + …Extension.php — config keys and defaults for layout.Form/Extension/ — the type extensions that add layout and context options.First use case: render a whole form with the default Bootstrap layout instead of hand-writing form-group/control-label wrappers:
{{ form(form) }}
{{ form(form, {layout: 'horizontal'}) }}
Per-form layout switching. The bundle's core design is "unobtrusive": no layout is forced. Defaults to the basic stacked layout; you opt into horizontal, inline, or navbar per render call. The Laravel analogue is a prop on a component:
{{-- resources/views/components/form/field.blade.php --}}
@props(['name', 'label' => null, 'layout' => 'default'])
@php $horizontal = $layout === 'horizontal'; @endphp
<div class="{{ $horizontal ? 'row mb-3' : 'mb-3' }}">
@if ($label)
<label for="{{ $name }}" @class(['col-sm-2 col-form-label' => $horizontal, 'form-label' => ! $horizontal])>
{{ $label }}
</label>
@endif
<div @class(['col-sm-10' => $horizontal])>
<input id="{{ $name }}" name="{{ $name }}" {{ $attributes->class(['form-control', 'is-invalid' => $errors->has($name)]) }}>
@error($name) <div class="invalid-feedback">{{ $message }}</div> @enderror
</div>
</div>
Button "context" as an enum-ish prop. The Symfony usage is 'context' => 'primary', mapped to btn-primary. In Blade, mirror it exactly so templates stay portable:
{{-- components/btn.blade.php --}}
@props(['context' => 'secondary', 'type' => 'submit'])
<button type="{{ $type }}" {{ $attributes->class(["btn btn-{$context}"]) }}>
{{ $slot }}
</button>
Layout as a form-level concern, not a field-level one. Symfony sets layout once and the theme propagates it. Do the same: put layout on the <form> wrapper component and pass it down via @aware/@props rather than repeating it on every field.
Global default via config. The bundle lets you set a project-wide default layout so you only override the exceptions. In Laravel put it in config/forms.php and read it in the component's @props default — one place to change, no per-call noise.
Keep assets out of the dependency. The bundle's own philosophy: it assumes Bootstrap is installed by Composer/Bower (today: npm + Vite). Follow that — npm i bootstrap, import in resources/js/app.js, and never let a UI package own your CSS pipeline.
form-group, control-label, has-error, col-md-*, btn-default, input-lg, pull-right. In Bootstrap 5 those are mb-3, form-label, is-invalid/invalid-feedback, btn-secondary, form-control-lg, float-end. A drop-in theme copy will look subtly broken; translate, don't paste.icon option renders glyphicon glyphicon-*, swap for an inline SVG or an icon package.{% form_theme form 'X' %} beats global twig.form_themes. In Blade the equivalent trap is component slot order and $attributes->class([...]) — later class merges append, so a hardcoded class="btn btn-primary" plus $attributes gives you btn btn-primary btn-danger. Always route variants through class([...]).form(form) only styles what the helpers render. Manually written <input> tags bypass the theme entirely — this is the #1 "why is my field unstyled" confusion.~0.1), README-only maturity, Symfony 2 era. Pin the exact version if you must use it, vendor the Twig theme files into your own bundle, and assume no upstream fixes — including for anything PHP 8 / Symfony 5+ related. Don't put it on a critical path.context, icon, layout) to every field without subclassing. The Laravel equivalent is a FormRequest-level macro or a Form::macro('contextButton', …), or simply the shared Blade component — one definition, available everywhere.field/btn component pair gets you the same behaviour with current Bootstrap and no dead Symfony coupling.How can I help you explore Laravel packages today?