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

Bootforms Laravel Package

adamwathan/bootforms

BootForms is a Laravel package for rapidly building Bootstrap-styled forms. Its fluent API handles fields, labels, help text, and validation errors, with model binding and sensible defaults that cut repetitive markup and keep forms clean and consistent.

View on GitHub
Deep Wiki
Context7

Getting Started

BootForms is a thin, chainable wrapper around laravelcollective/html's FormBuilder that emits Bootstrap 3 markup (form-group, control-label, help-block, has-error) and wires in Laravel's validation MessageBag. It is a convenience layer, not a form framework — it generates HTML strings you echo in Blade.

  1. Install both packages. BootForms does not bundle the underlying form builder:

    composer require adamwathan/bootforms laravelcollective/html
    

    The last release is from 2017 and targets Laravel 5.x. If you are on Laravel 6+, check composer why-not and expect to pin laravelcollective/html to a compatible major. Do this before writing any forms.

  2. Register the service provider and facade (Laravel 5.4 and earlier; on 5.5+ package discovery may handle it):

    AdamWathan\BootForms\BootFormsServiceProvider::class,
    'BootForms' => AdamWathan\BootForms\Facades\BootForms::class,
    
  3. Read these first, in order: the BootFormsBuilder class (the facade root — it forwards unknown calls to Form::), the FormGroup class (where label/help/error markup is assembled), and the FormOpen class (action/route/method/multipart handling). Almost every quirk you hit lives in FormGroup.

  4. First use case — a horizontal create form with a bound model and automatic error display:

    {!! BootForms::horizontal()->open()->route('users.store') !!}
    
    {!! BootForms::text('name')->label('Name')->placeholder('Jane Doe') !!}
    {!! BootForms::email('email')->label('Email') !!}
    {!! BootForms::password('password')->label('Password') !!}
    
    {!! BootForms::submit('Create User')->addClass('btn-primary') !!}
    {!! BootForms::close() !!}
    

    If $errors is shared (Laravel 5.4+), the fields pick up validation state automatically. On older versions pass the bag explicitly with ->errors($errors).

Implementation Patterns

Model binding. Set the model once and all subsequent fields read from it:

{!! BootForms::model($user)->text('name') !!}
{!! BootForms::model($user)->email('email') !!}

This is the single biggest day-to-day win: one partial for both create and edit. Keep the model() call adjacent to the field so the binding context is obvious when reading the template.

Field chaining. Every field returns a FormGroup, so options compose:

{!! BootForms::text('title')
    ->label('Post Title')
    ->helpBlock('Keep it under 60 characters.')
    ->placeholder('My first post')
    ->required() !!}

Use ->value() only when you intentionally want to override model/old-input resolution — the ordering of value() versus model() matters.

Horizontal layout. Call ->horizontal() at the form or field level and the builder splits label and control into Bootstrap grid columns. Configure the default widths once in a service provider so you don't repeat them on hundreds of fields:

BootForms::defaultFormGroupClass('form-group');
BootForms::defaultLabelClass('control-label');

Validation display. Prefer server-side FormRequest validation plus a redirect with errors; BootForms then just renders the has-error class and the first message. Add explicit bags for multi-form pages:

{!! BootForms::text('name')->errors($errors->profile) !!}

Reusable field partials. For fields used in several forms, wrap the chain in a Blade partial that accepts a pre-built FormGroup:

{{-- resources/views/partials/field.blade.php --}}
{!! $field !!}

Compose the chain in the parent. The alternative — passing field type and name into the partial — loses the fluent API and is usually worse.

Create/edit parity. A single _form.blade.php that opens with model() and closes with a submit button covers both create and edit. Detect the mode only for the submit label:

{!! BootForms::submit($user->exists ? 'Update' : 'Create') !!}

Custom controls. When BootForms doesn't wrap a control you need, fall back to the underlying builder and keep the markup consistent:

{!! BootForms::text('slug')->addClass('slug-input') !!}

For one-off HTML controls, render the Bootstrap form-group wrapper yourself and reserve BootForms for the fields it handles well. Don't fight it.

Extending. Because the facade proxies to Form, macros registered on the FormBuilder are reachable through BootForms. If you need genuinely new behavior (a custom file upload widget, a date-range field), subclass BootFormsBuilder and rebind the facade rather than patching vendor code.

Gotchas and Tips

  • Archived and unmaintained. No fixes for modern Laravel, PHP 8.x notices, or Bootstrap 4/5 markup. Treat it as a legacy-tier dependency: acceptable in a brownfield Laravel 5 app, a poor choice for a new build. The viable modern replacements are Laravel Blade components, spatie/laravel-html, or Laravel Collective's own newer tooling.

  • Bootstrap 3 markup only. It emits form-group/has-error/help-block. Bootstrap 4+ renamed these to form-group/invalid-feedback/is-invalid. Do not assume upgrading Bootstrap in CSS is harmless — the error states will silently stop styling.

  • $errors is not always present. On older Laravel versions the shared view variable doesn't exist, and BootForms will not invent it. Either pass ->errors($errors) everywhere or share the bag from a view composer. This is the most common "why is nothing red?" bug.

  • Array field names break error lookup. items[0][name] does not map cleanly to the items.0.name key in the MessageBag. For nested/repeating fields, render the error state manually with ->addClass($errors->has('items.0.name') ? 'has-error' : '') or drop to hand-written markup.

  • Method spoofing and multipart. Use the FormOpen options, not raw attributes:

    {!! BootForms::open()->route('users.update', $user)->method('PUT')->multipart() !!}
    
  • CSRF is automatic for POST. If you build the opening tag by hand "just once," you will forget the token. Keep everything going through BootForms::open().

  • Checkbox semantics are inverted from your intuition. The label renders next to the box and the value() must be set explicitly; unchecked boxes submit nothing, so validate with sometimes|accepted or a hidden zero-value input. Test the unchecked case — it is the classic BootForms bug report.

  • Chain order is not cosmetic. ->value() after ->model() wins; ->label() before the field renders nothing if you reassign the return value incorrectly. Always echo the final chained expression, not an intermediate variable.

  • Debugging rendering issues. dd((string) BootForms::text('name')) prints the exact HTML. Do this before assuming a CSS problem. If the markup looks right but the error class is missing, the issue is the MessageBag, not the builder.

  • Config quirks. Default classes and column widths are configurable through the builder's default* setters; set them in a service provider, not per-view. If you publish a config file, check that the keys match the version you installed — the 2017 release predates several Laravel config conventions.

  • Don't mix Form:: and BootForms:: for related fields. BootForms tracks state (model, horizontal mode) internally. Interleaving raw Form::text() calls produces markup that looks fine until the first validation error, then diverges. Pick one per form.

  • Testing. Assert on rendered HTML fragments (assertSee('has-error')) rather than internal builder state; the builder's API is undocumented enough that brittle unit tests will break on any dependency bump — and there will be no upstream fixes to help you.

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.
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle