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

Form Laravel Package

steelants/form

Steelants Form is a Laravel package for building and managing forms, offering a simple way to define fields, handle validation, and render form markup in your PHP applications. Lightweight and easy to integrate.

View on GitHub
Deep Wiki
Context7

Getting Started

This is a single-maintainer package (1 star, 0 dependents, no ecosystem around it). Treat the source as the documentation — budget an hour to read src/ before you commit to it.

Install and confirm discovery

composer require steelants/form

Then immediately check two files:

  1. vendor/steelants/form/composer.json — look at extra.laravel.providers / extra.laravel.aliases. If they're absent, you must register the service provider in config/app.php manually (or in bootstrap/providers.php on Laravel 11+).
  2. vendor/steelants/form/src/ — find the main builder class (likely Form.php or similar) and the Blade views, if any. This class's public methods are the API.

Check for publishable assets

php artisan vendor:publish --provider="Steelants\Form\FormServiceProvider"

If nothing publishes, the package renders markup inline and you have no view overrides — plan to subclass or fork for customization.

Smoke test before integrating

Drop a throwaway route and render one field of each type to see the actual HTML:

Route::get('/form-check', function () {
    return \Steelants\Form\Form::text('name', 'Name');
});

Inspect the output against Bootstrap 5 form docs. Confirm it emits form-label, form-control, invalid-feedback — not the Bootstrap 4 form-group / form-text vocabulary. If it's emitting BS4 classes, that's your first bug to patch.

First real use case

The highest-value application is a create/edit CRUD form where you currently hand-write Bootstrap markup. Rewrite one form (not all of them) and measure:

  • Did the builder handle old() repopulation and $errors binding automatically, or did you still write it?
  • How many lines did you actually save versus a plain Blade partial with a <x-input> component?

If the answer to the second question is "few or none," a two-file Blade component will serve you better than an unmaintained dependency.

Implementation Patterns

Where to instantiate the builder

Prefer building in the controller or a form-request-adjacent presenter, not in the Blade view. Keeping the form definition in PHP makes it testable and keeps the template to a single {!! $form !!} or a loop. If the package only supports view-time usage, at least extract it to a partial so you can swap it out later.

// Controller
public function edit(Post $post)
{
    return view('posts.edit', [
        'post' => $post,
        'form' => Form::model($post)->route('posts.update', $post)->method('PUT'),
    ]);
}

Field chaining is the natural style

Most builders of this vintage are fluent. Expect something close to:

{!! Form::open()->route('posts.store')->multipart() !!}
{!! Form::text('title')->label('Title')->required()->help('Max 120 characters') !!}
{!! Form::textarea('body')->label('Body')->rows(8) !!}
{!! Form::select('status', ['draft' => 'Draft', 'published' => 'Published'])->label('Status') !!}
{!! Form::checkbox('is_featured')->label('Feature this post') !!}
{!! Form::submit('Save')->class('btn btn-primary') !!}
{!! Form::close() !!}

Verify each method name against the source before writing twenty forms against a guessed API.

Repopulation is the thing to test first

The two behaviors that decide whether this package is worth it:

  • On validation failure, does Form::text('title') pick up old('title') automatically? If not, you must pass old('title', $post->title ?? '') on every field — which erases most of the benefit.
  • Does it add is-invalid plus an invalid-feedback div from the $errors bag? If not, you're writing that per field anyway.

If both are missing, write a Blade component instead. It's ~40 lines and you control it.

Layout with Bootstrap 5 grid

BS5 dropped form-group and form-row. Wrap fields yourself:

<div class="row g-3">
    <div class="col-md-8">{!! Form::text('title')->label('Title') !!}</div>
    <div class="col-md-4">{!! Form::select('status', $statuses)->label('Status') !!}</div>
</div>

This keeps layout concerns (grid) with the template and field concerns (input, label, errors) with the builder — a division of labor that survives replacing the package later.

Method spoofing and CSRF

PUT/PATCH/DELETE forms need @method and @csrf. Confirm the builder's open() emits both, or add them inside the open/close pair manually. This is a common gap in small form packages and a silent 419/405 source.

File uploads

If you use ->file() or ->multipart(), verify the enctype actually lands on the <form> tag and not just the input.

Testing rendered output

Since there's no test suite you can trust, write your own thin assertions:

$response = $this->get('/posts/create');
$response->assertSee('name="title"', false);
$response->assertSee('class="form-control', false);
$response->assertSee('name="_token"', false);

Do this once per field type. It's cheap and it catches the package silently changing behavior on a minor bump.

Extension strategy

Because you'll almost certainly need to change something, pick an extension point deliberately, in this order of preference:

  1. Macros — if the class uses Macroable, register Form::macro('currency', ...) in a service provider.
  2. Subclass — extend the builder, override the render methods, and bind your subclass in the container.
  3. Fork — for anything structural. The package is MIT and tiny; a fork in app/Support/ is often cheaper than fighting it.

Gotchas and Tips

Adoption risk is the headline, not a footnote. One star, zero dependents, no issue activity means no security review, no Laravel 11/12 compatibility guarantee, and no fix coming when Bootstrap ships a breaking change. Read composer.json's require block and confirm the illuminate/* constraints actually permit your Laravel version before you build on it. Pin the exact version in composer.json rather than floating ^1.0.

Bootstrap version drift. The description says BS5, but verify the emitted classes. Watch specifically for: form-group (BS4, removed), form-row (BS4), custom-select (BS4 → form-select in BS5), custom-checkbox (BS4 → form-check), invalid-feedback (correct in both, but only shown when the sibling input has is-invalid). A mismatch means your forms render subtly wrong and nobody notices until QA.

Escaping. Check whether label text and attribute values go through e() / htmlspecialchars. A form builder that concatenates strings is one user-supplied label away from stored XSS. Grep the source for htmlspecialchars, e(, and raw sprintf/concatenation into HTML.

Old input and error bags are not guaranteed. Test the failure path, not the happy path: submit an invalid form and look at the rendered HTML. If the input value doesn't return and the error message doesn't render, the package isn't buying you much.

CSRF silent failure. If open() doesn't emit @csrf, every POST 419s and the error page tells you nothing useful. Check immediately.

Config caching and provider registration. If the facade alias isn't registered, you get Class "Form" not found — and php artisan config:clear won't help because it's a provider issue, not config. If you edit config/app.php on Laravel 11+, remember bootstrap/providers.php is the modern location.

No published views means no easy overrides. If you can't vendor:publish the Blade templates, your only customization paths are subclassing or forking. Decide which one before you've written thirty forms against the default markup.

Debugging rendered HTML. When a field comes out wrong, dd() the builder instance to see the accumulated attributes before rendering:

dd(Form::text('title')->label('Title'));

Then compare against what ->render() produces. This is faster than reading the class.

Write a wrapper even if you don't fork. Put a single App\Support\Form class in front of the package that proxies the calls you use. When the package breaks — or when you decide to migrate to a Blade component — you change one file instead of every view. Given the maintenance profile here, this is the highest-leverage thing you can do on day one.

Have an exit plan. The realistic migration target is a pair of anonymous Blade components (<x-form.input>, <x-form.select>) plus @csrf/@method. Keep your form definitions in a shape that maps cleanly to that, and the package becomes a short-term convenience rather than a long-term liability.

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.
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
cgv/localized-resource