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

Html Laravel Package

laravie/html

Laravie HTML provides convenient HTML and form builders for Laravel, with a fluent, expressive API for generating forms, inputs, buttons, and other markup in your views. It keeps templates clean, supports model binding and old input, and integrates smoothly with Laravel validation and routing conven...

View on GitHub
Deep Wiki
Context7

Getting Started

Install and confirm the wiring

composer require laravie/html

If you're on Laravel 9, pin the version explicitly — v7.3.0 is the release that added Laravel 9 support, so older constraints will fail to resolve or install a package that can't boot:

composer require laravie/html:^7.3

Laravel auto-discovery registers Laravie\Html\HtmlServiceProvider, and the package declares Form / HTML facade aliases. If your app doesn't pick them up (older skeleton, or aliases disabled), add them manually:

// config/app.php
'aliases' => [
    'Form' => Laravie\Html\Facades\Form::class,
    'HTML' => Laravie\Html\Facades\HTML::class,
],

First smoke test — drop this into any Blade view and load the page:

{!! Form::open(['route' => 'posts.store']) !!}
    @csrf
    {!! Form::label('title', 'Title') !!}
    {!! Form::text('title', null, ['class' => 'form-control']) !!}
    {!! Form::submit('Save', ['class' => 'btn btn-primary']) !!}
{!! Form::close() !!}

Note the {!! !!} delimiters — the builders return markup, not escaped values. Everything in this package is a string builder for Blade; it is not a response/validation layer.

Where to look first

  1. vendor/laravie/html/src/FormBuilder.php and HtmlBuilder.php — the authoritative method list. The README shows a subset; the source shows the exact signatures ($name, $value = null, $attributes = [] ordering, which methods accept a $selected argument, etc.).
  2. The facade classes in src/Facades/ to confirm the container binding names if you prefer injecting the builder into a view composer or a custom Blade directive.
  3. config/app.php aliases (above) — the number one "why is Form:: undefined" cause.

First real use case — converting a hand-written edit form to model-bound fields. Replace value="{{ old('title', $post->title) }}" boilerplate everywhere with:

{!! Form::model($post, ['route' => ['posts.update', $post], 'method' => 'PUT']) !!}

The builder then resolves every field value itself: old input first, then the model attribute, then the explicit default.

Implementation Patterns

One form, one open/close pair. Treat Form::open() as a scoped session that Form::close() ends. Put the open at the top of the form partial and the close at the bottom, and never nest forms.

{!! Form::open([
    'url' => route('posts.store'),
    'method' => 'POST',          // emits _method spoofing for PUT/PATCH/DELETE
    'files' => true,             // adds enctype="multipart/form-data"
    'class' => 'form',
    'novalidate' => true,
]) !!}

Model binding for edit forms. This is the highest-value feature; use it consistently.

{!! Form::model($post, ['route' => ['posts.update', $post], 'method' => 'PUT']) !!}
    {!! Form::text('title', null, ['class' => 'form-control']) !!}
    {!! Form::textarea('body', null, ['rows' => 8]) !!}
    {!! Form::select('status', $statuses, null, ['placeholder' => 'Choose…']) !!}
{!! Form::close() !!}

Value resolution is: flashed old input → bound model attribute → the value argument. That means you get repopulation-on-validation-failure for free and should stop writing old(...) inside form partials at all. Explicit values still win when you pass them, so keep null unless you truly want to override.

For nested attributes, use dot/bracket notation (Form::text('author[name]')) and confirm against the builder source whether your version resolves it via data_get on the model.

Selects from Eloquent. Build the options array explicitly — don't rely on the builder accepting a Collection:

{!! Form::select('user_id', $users->pluck('name', 'id')->all(), null, ['class' => 'form-select']) !!}

Checkboxes and radios. Remember that an unchecked checkbox submits nothing. For booleans, pair it with a hidden field:

{!! Form::hidden('published', 0) !!}
{!! Form::checkbox('published', 1, null) !!}

Then read with $request->boolean('published').

Wrap repetitive fields in macros. Register once in a service provider's boot() — macros are bound to the builder instance, so $this gives you the other builder methods:

use Laravie\Html\Facades\Form;

public function boot(): void
{
    Form::macro('bsText', function ($name, $label, $value = null, $attributes = []) {
        $attributes = array_merge(['class' => 'form-control'], $attributes);
        $error = $this->error ?? null;

        return $this->label($name, $label)
             . $this->text($name, $value, $attributes);
    });
}

Then {!! Form::bsText('title', 'Title') !!}. Do the same with HTML::macro() for repeated card/badge/list markup.

For anything stateful or conditional, wrap the macro in a Blade component. A <x-form.field> component that calls Form::text() internally is easier to evolve than a macro when you need @error-driven is-invalid classes:

{{-- resources/views/components/form/field.blade.php --}}
@props(['name', 'label'])
<label for="{{ $name }}">{{ $label }}</label>
{!! Form::text($name, null, [
    'id' => $name,
    'class' => 'form-control' . ($errors->has($name) ? ' is-invalid' : ''),
]) !!}
@error($name) <div class="invalid-feedback">{{ $message }}</div> @enderror

HTML facade for links, media and lists — mainly useful for attribute-array consistency:

{!! HTML::link(route('home'), 'Home', ['class' => 'nav-link']) !!}
{!! HTML::image(asset('img/logo.png'), 'Logo', ['class' => 'logo', 'width' => 120]) !!}
{!! HTML::ul($tags, ['class' => 'tags'], fn ($tag) => HTML::linkRoute('tags.show', $tag->name, $tag)) !!}

Keep it in views. These builders return strings, not responses. Don't call them from controllers or API resources; if you need markup outside Blade, render a view that uses them.

Testing. Rendered markup is plain HTML, so assert on it directly — $response->assertSee('name="title"', false). For unit-level checks of a custom macro, Form::text('x') returns a string you can compare or assertStringContainsString against.

Gotchas and Tips

  • Escaping. Always {!! !!}. Some methods return Illuminate\Support\HtmlString (which Blade renders unescaped even with {{ }}), others return plain strings (which would be escaped). {!! !!} is the only delimiter that's correct for both — use it uniformly.
  • Platform support. v7.3.0 explicitly adds Laravel 9 support — that's the minimum version to install on a Laravel 9 app, and the release notes don't indicate anything newer. There's no stated support for Laravel 10+, so on 10/11 check composer.json's illuminate/* constraints before committing; if the constraint blocks install, that's your signal to evaluate alternatives rather than force --ignore-platform-reqs. Laravel 9 requires PHP 8.0+, and 8.2+ dynamic-property deprecations are still worth watching for if the package sets undeclared properties.
  • Alias collision with laravelcollective/html. Both register Form and HTML. Remove the old package (or the old aliases) before adding this one, otherwise you'll silently get the wrong builder and confusing missing-method errors. This matters more during the Laravel 8→9 upgrade window, where both packages may be present at different versions.
  • CSRF. Verify whether Form::open() in your installed version auto-appends the token hidden input. If it does, adding @csrf gives you a duplicate _token field; if it doesn't, forgetting it gives you a 419 that looks like a middleware problem. Check the generated HTML for _token once and settle on one approach — and re-check it after the 8→9 upgrade, since middleware/session handling changed around those releases.
  • Never leave a form unclosed. Form::model() sets the bound model on the builder. If you return early from a partial or throw before Form::close(), a later form on the same page can inherit the wrong model. Form::close() is what resets that state — put it in the same partial as the open.
  • Type juggling in selects. Model attribute 1 (int) vs. option key "1" (string) determines whether an option is marked selected. When a pre-selection doesn't appear, dd(Form::select(...)) and compare the raw types before opening a bug.
  • Collections vs. arrays. Convert with ->pluck(...)->all() rather than assuming the builder accepts Collection/Arrayable; passing the wrong type usually produces an empty <select> with no error.
  • Attribute semantics. null attribute values are dropped (good for conditionally adding disabled); booleans render as disabled="1" style values, which is valid but noisy. Prefer 'disabled' => 'disabled' when you care about the output, and remember data-*/aria-*/wire:model pass through untouched.
  • Macros can't shadow real methods. Macroable::__call only fires for undefined methods, so name custom macros distinctly (e.g. bsText, not text). Register them in a provider's boot(), never inside a Blade @php block — that re-registers per render and breaks under view caching/Octane.
  • Debugging output. dd(Form::text('title', null, ['class' => 'x'])) is the fastest way to see exactly what attributes and values were resolved — far quicker than reading the source when a value "doesn't populate".
  • Livewire/Alpine forms. Old-input repopulation can fight client-side state. For Livewire components, prefer plain HTML inputs with wire:model and reserve this package for classic controller-rendered forms.
  • Security. The builder escapes attribute values, but you defeat that the moment you {!! !!} output around raw user input or concatenate untrusted strings into an attribute array. Treat HTML::decode()-style helpers as "trusted content only".
  • Extension points to remember: Form::macro, HTML::macro, the underlying builders ($this->text(), $this->label(), $this->attributes()), and publishing/tuning any package config if your version ships one. Between macros and Blade components you can cover nearly every repeating form pattern without touching vendor code.
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.
robertmarney/lara-hierarchial-collections
simonschaufi/rule-doc-generator
emissaoja/emissaoja
blackbricksoftware/gravityforms-civicrm-form-processor
al-rahabi/fancy-crud
jinas/dhivatar-component
mltstephane/laravel-quality
bernskiold/laravel-talentlms
bernskioldmedia/laravel-form-architect
youbar/easy-crud
c-point-labs/laravel-hostyourai
dbravoan/dbcms-admin-theme-dbcms
dbravoan/dbcms-theme-db-cyber
dbravoan/dbcms-blocks-basic
dbravoan/dbcms-module-content-audit
dbravoan/dbcms-module-ai-assistant
paygate-to/paygate-php
padosoft/askmydocs-connector-base
defstudio/supercharged-carbon
bernskioldmedia/laravel-matomo