spatie/laravel-html
Generate HTML in Laravel with a clean, readable API. Build elements dynamically and compose them easily, including form fields that automatically pull values from models, session data, or defaults. Includes a convenient Html facade/alias for quick use.
Start by installing the package via Composer: composer require spatie/laravel-html. After installation, the html() helper function becomes available globally—no manual facade registration needed (though the old Html facade is still supported via Spatie\Html\Facades\Html::class). Your first use case will almost certainly be building dynamic forms or reusable UI components:
// Basic element creation
echo html()->input('text', 'name')->value('John')->render();
// "<input type="text" name="name" value="John">"
// Building a form field with error awareness (via old() and model binding)
$email = html()->email('email', 'user@example.com');
// If form fails validation, old('email') is used automatically; otherwise falls back to default
Read the html() helper documentation first—it’s the entry point for all element creation. Understand immutability: every method call (e.g., class(), value()) returns a new element instance, not mutating the original.
html()->select('status', $user->status)—the package intelligently pulls old() values, selected values, and defaults in order of priority.@include with inline builders for modular UI:<div class="card">
{{ html()->div()->class('card-body')
->children(['Title' => html()->h2('Info'), 'Body' => html()->p($description)]) }}
</div>
class() or classes() (via array/collection) for conditional utility classes:html()->button('Submit')
->class(['btn', 'btn-primary' => $isValid, 'btn-disabled' => !$isValid])
->disabled(!$isValid)
Spatie\Html\Html (as shown in docs) to register domain-specific methods like radioYesNo($name). Bind the extended class via AppServiceProvider’s singleton to override the default html() helper globally.if() to compose elements with minimal branching:html()->div()->if($isUserLoggedIn, fn($div) => $div->text('Welcome back, ' . $user->name))
$input = $input->class('new-class');, not $input->class('new-class') alone.name: html()->email('email') sets both name and id; omitting the first argument produces invalid markup. Double-check when building dynamic fields.html(): When embedding rendered HTML in Blade, use {!! !!} or explicitly call ->render() (returns HtmlString) to avoid double-escaping. text() always escapes, html() does not—mix carefully.Div::create() over Element::withTag('div') for brevity, but note create() is only available on concrete element classes (not generic Element).attributes() or children() methods to accept different iterables.->getAttribute('class') or ->getAttribute('data-id') to inspect attribute values mid-chain without rendering—useful in TDD.->close() returns empty string for void elements like <img>, <br>, or <input>—don’t manually close them.How can I help you explore Laravel packages today?