# Laravel HTML Builder ## Introduction Laravel HTML is a fluent HTML builder package for Laravel applications that provides a clean, chainable API for generating HTML elements dynamically. The package focuses on making HTML and form generation painless by offering an expressive syntax that eliminates the need for manual string concatenation and reduces errors in HTML markup. It integrates seamlessly with Laravel's ecosystem, automatically handling CSRF tokens, HTTP method spoofing, old input values from failed form submissions, and model attribute binding. The library follows immutability principles where each method call returns a new instance, making it safe to reuse element definitions throughout your application. All HTML elements are generated through a central `Html` builder class, which can be accessed via the `html()` helper function or the `Html` facade. Elements support extensive customization through fluent method chaining for attributes, classes, styles, data attributes, and nested children, making it ideal for both simple and complex HTML generation scenarios. ## API Reference and Code Examples ### Creating Basic HTML Elements Generate standard HTML elements with optional content and attributes. ```php use Spatie\Html\Facades\Html; // Create a link echo html()->a('https://example.com', 'Visit Site'); // Visit Site // Create a div with content echo html()->div('Hello World')->class('container'); //
Hello World
// Create a span with attributes echo html()->span('Badge')->class('badge badge-primary')->id('user-badge'); // Badge // Create a paragraph echo html()->p('This is a paragraph')->style('color: red'); //

This is a paragraph

// Create a button echo html()->button('Click Me', 'button')->class('btn btn-primary')->disabled(); // // Create a mailto link echo html()->mailto('hello@example.com', 'Contact Us'); // Contact Us // Create a tel link echo html()->tel('+1234567890', 'Call Us'); // Call Us // Create a custom element echo html()->element('article')->class('post')->html('

Title

'); //

Title

``` ### Building Forms with Automatic CSRF Protection Create forms with automatic CSRF token injection and HTTP method spoofing. ```php // Basic POST form echo html()->form('POST', '/users')->open(); echo html()->text('username')->placeholder('Enter username'); echo html()->submit('Create User'); echo html()->form()->close(); // Output: //
// // // //
// Form with method spoofing for PUT/PATCH/DELETE echo html()->form('PUT', '/users/1')->open(); echo html()->email('email')->required(); echo html()->submit('Update'); echo html()->form()->close(); // Output: //
// // // // //
// GET form (no CSRF token) echo html()->form('GET', '/search')->open(); echo html()->search('query')->placeholder('Search...'); echo html()->submit('Search'); echo html()->form()->close(); // Output: //
// // //
// Form with route helper echo html()->form('POST')->route('user.store')->open(); // Uses Laravel's route() helper to resolve the URL // Form with file upload support echo html()->form('POST', '/upload')->acceptsFiles()->open(); echo html()->file('avatar')->required(); echo html()->submit('Upload'); echo html()->form()->close(); // Adds enctype="multipart/form-data" to the form ``` ### Model-Bound Forms with Auto-Population Bind forms to Eloquent models for automatic field population from model attributes. ```php // Create a model-bound form $user = User::find(1); // User with name="John Doe", email="john@example.com" echo html()->modelForm($user, 'PUT', '/users/1')->open(); echo html()->text('name'); echo html()->email('email'); echo html()->select('status', ['active' => 'Active', 'inactive' => 'Inactive']); echo html()->closeModelForm(); // Output: //
// // // // // //
// Manual model binding html()->model($user); echo html()->text('name'); // Automatically uses $user->name echo html()->password('password'); // Passwords never auto-populate html()->endModel(); // Nested attributes with array notation $profile = ['user' => ['address' => ['city' => 'New York']]]; html()->model($profile); echo html()->text('user[address][city]'); // // Enum support (PHP 8.1+) enum Status: int { case Pending = 1; case Complete = 2; } $task = Task::find(1); // Task with status = Status::Pending html()->model($task); echo html()->select('status', [ Status::Pending->value => 'Pending', Status::Complete->value => 'Complete' ]); // Automatically selects the option matching Status::Pending->value ``` ### Input Fields with Various Types Generate input fields with automatic old value population and validation attributes. ```php // Text input with attributes echo html()->text('username', 'default_value') ->placeholder('Enter username') ->class('form-control') ->required() ->autofocus() ->maxlength(50); // // Email input echo html()->email('email')->required()->autocomplete('email'); // // Password input (never shows old values) echo html()->password('password')->required()->minlength(8); // // Hidden input echo html()->hidden('user_id', 42); // // Number input with constraints echo html()->number('quantity', 1, 1, 100, 1) ->placeholder('Quantity') ->required(); // // Range slider echo html()->range('volume', 50, 0, 100, 5); // // Date input with automatic formatting $date = '2024-01-15 10:30:00'; echo html()->date('birthday', $date); // // DateTime input echo html()->datetime('appointment', '2024-01-15 10:30:00'); // // Time input echo html()->time('opening_time', '09:00:00'); // // File upload echo html()->file('avatar')->accept('image/*'); // // Search input echo html()->search('q')->placeholder('Search...'); // ``` ### Checkboxes and Radio Buttons Create checkbox and radio inputs with automatic checked state handling. ```php // Basic checkbox echo html()->checkbox('agree', false, '1'); // // Checked checkbox echo html()->checkbox('subscribe', true, 'yes'); // // Checkbox with custom value echo html()->checkbox('terms', false, 'accepted')->required(); // // Radio button echo html()->radio('gender', false, 'male'); echo html()->radio('gender', false, 'female'); // // // Radio with one selected echo html()->radio('status', true, 'active'); echo html()->radio('status', false, 'inactive'); // // // Radio buttons with labels $options = ['small' => 'Small', 'medium' => 'Medium', 'large' => 'Large']; foreach ($options as $value => $label) { echo html()->label([ html()->radio('size', $value === 'medium', $value), ' ' . $label ]); } ``` ### Select Dropdowns with Options Generate select elements with simple arrays, nested optgroups, and automatic selection. ```php // Basic select with options $options = [ 'us' => 'United States', 'ca' => 'Canada', 'mx' => 'Mexico' ]; echo html()->select('country', $options, 'us'); // // Select with placeholder echo html()->select('city', $options)->placeholder('Select a city'); // Adds an empty option at the beginning // Required select echo html()->select('category', $options)->required(); // // Multiselect echo html()->multiselect('tags[]', [ 'php' => 'PHP', 'laravel' => 'Laravel', 'javascript' => 'JavaScript' ], ['php', 'laravel']); // // Select with optgroups $groupedOptions = [ 'Fruits' => [ 'apple' => 'Apple', 'banana' => 'Banana' ], 'Vegetables' => [ 'carrot' => 'Carrot', 'lettuce' => 'Lettuce' ] ]; echo html()->select('food', $groupedOptions, 'apple'); // // Select with Laravel Collection $users = User::all()->pluck('name', 'id'); echo html()->select('user_id', $users); ``` ### Textarea with Content Create textarea elements with automatic value population and constraints. ```php // Basic textarea echo html()->textarea('description', 'Default text'); // // Textarea with attributes echo html()->textarea('bio') ->placeholder('Tell us about yourself') ->rows(5) ->class('form-control') ->required() ->maxlength(500); // // Read-only textarea echo html()->textarea('terms', 'Terms and conditions...') ->readonly(); // ``` ### Labels, Fieldsets, and Form Structure Organize form elements with semantic HTML structure. ```php // Label with for attribute echo html()->label('Email Address', 'email')->class('form-label'); // // Label wrapping an input echo html()->label([ html()->checkbox('remember', false, '1'), ' Remember me' ]); // // Fieldset with legend echo html()->fieldset('Personal Information') ->addChild(html()->label('Name', 'name')) ->addChild(html()->text('name')) ->addChild(html()->label('Email', 'email')) ->addChild(html()->email('email')); //
// Personal Information // // // // //
// Submit and reset buttons echo html()->submit('Save Changes')->class('btn btn-primary'); // echo html()->reset('Clear Form')->class('btn btn-secondary'); // ``` ### Element Attributes and Chaining Manipulate element attributes using fluent method chaining and conditional methods. ```php // Setting multiple attributes $input = html()->text('username') ->class('form-control') ->id('user-input') ->attribute('data-validate', 'required') ->data('max-length', '50') ->aria('label', 'Username input'); // // Conditional attributes $isRequired = true; echo html()->email('contact') ->requiredIf($isRequired) ->classIf($isRequired, 'required-field'); // // Unless conditions $isDisabled = false; echo html()->button('Submit') ->disabledUnless(!$isDisabled) ->classUnless($isDisabled, 'btn-active'); // Conditional with null check $placeholder = 'Enter email'; echo html()->email('email')->placeholderIfNotNull($placeholder); // Style attribute echo html()->div('Content') ->style(['color' => 'red', 'font-size' => '14px']); //
Content
echo html()->span('Text')->style('font-weight: bold'); // Text // Adding multiple classes echo html()->div()->class('container')->class('mx-auto')->class('p-4'); //
// Removing attributes $element = html()->text('name')->required(); $element = $element->forgetAttribute('required'); // ``` ### Building Nested Elements Create complex HTML structures with nested children elements. ```php // Adding children to elements echo html()->div() ->class('card') ->addChild(html()->div('Header')->class('card-header')) ->addChild(html()->div('Body content')->class('card-body')) ->addChild(html()->div('Footer')->class('card-footer')); //
//
Header
//
Body content
// //
// Using children() method with array echo html()->div([ html()->span('Item 1'), html()->span('Item 2'), html()->span('Item 3') ])->class('items'); //
// Item 1 // Item 2 // Item 3 //
// Prepending children echo html()->div() ->addChild(html()->p('Second')) ->prependChild(html()->p('First')); //
//

First

//

Second

//
// Complex nested structure echo html()->form('POST', '/submit')->open(); echo html()->div([ html()->fieldset('User Details')->addChild([ html()->label('Name', 'name'), html()->text('name')->required(), html()->label('Email', 'email'), html()->email('email')->required() ]), html()->div([ html()->submit('Save')->class('btn-primary'), html()->reset('Cancel')->class('btn-secondary') ])->class('form-actions') ])->class('form-container'); echo html()->form()->close(); // Conditional children $showExtra = true; echo html()->div() ->addChild(html()->p('Always visible')) ->addChildIf($showExtra, html()->p('Conditionally visible')); ``` ### Element Immutability and Reusability Leverage immutable element instances for safe reuse across your application. ```php // Elements are immutable - each method returns a new instance $baseButton = html()->button('Click')->class('btn'); $primaryButton = $baseButton->class('btn-primary'); $secondaryButton = $baseButton->class('btn-secondary'); echo $primaryButton; // echo $secondaryButton; // echo $baseButton; // // Reusable form field templates $formControl = fn($type, $name) => html()->input($type, $name) ->class('form-control') ->required(); echo $formControl('text', 'username'); echo $formControl('email', 'email'); // Icon pattern $icon = html()->i()->class('fa'); echo $icon->class('fa-home'); // echo $icon->class('fa-user'); // echo $icon->class('fa-search'); // ``` ### Opening and Closing Tags Generate separate opening and closing tags for template flexibility. ```php // Using open() and close() methods echo html()->div()->class('container')->open(); echo '

Content goes here

'; echo '

More content

'; echo html()->div()->close(); // Output: //
//

Content goes here

//

More content

//
// Form with open/close echo html()->form('POST', '/submit')->class('user-form')->open(); // ... blade template content ... echo html()->form()->close(); // Fieldset pattern echo html()->fieldset()->open(); echo html()->legend('Section Title'); // ... form fields ... echo html()->fieldset()->close(); ``` ### Extending the HTML Builder Extend functionality using Laravel's Macroable trait for custom element methods. ```php use Spatie\Html\Facades\Html; use Spatie\Html\Elements\Input; // Register a macro on the Html builder Html::macro('bootstrap5Input', function ($name, $label, $value = null) { return html()->div([ html()->label($label, $name)->class('form-label'), html()->text($name, $value)->class('form-control'), ])->class('mb-3'); }); // Use the macro echo html()->bootstrap5Input('username', 'Username', 'john_doe'); //
// // //
// Register element-level macro Input::macro('bootstrap', function () { return $this->class('form-control')->attribute('data-bs-theme', 'dark'); }); echo html()->text('email')->bootstrap(); // // Custom element shortcut Html::macro('alertBox', function ($message, $type = 'info') { return html()->div($message) ->class("alert alert-{$type}") ->attribute('role', 'alert'); }); echo html()->alertBox('Operation successful!', 'success'); // ``` ### Working with Old Input Values Automatic integration with Laravel's session flash data for form repopulation. ```php // When validation fails, Laravel redirects with old input // The HTML builder automatically uses these values // In your controller after validation fails: // return redirect()->back()->withInput(); // Your view will automatically repopulate: echo html()->text('username'); // Uses old('username') automatically echo html()->email('email'); // Uses old('email') automatically // Manual old value retrieval $value = html()->value('field_name', 'default'); // Equivalent to: old('field_name', 'default') // Old values work with model binding // Priority: old() > model attribute > default value $user = User::find(1); html()->model($user); echo html()->text('name'); // If old('name') exists, uses that, otherwise uses $user->name // Array field names are converted echo html()->text('user[profile][city]'); // Internally converts to old('user.profile.city') ``` ## Summary and Integration Patterns Laravel HTML Builder streamlines HTML generation in Laravel applications by providing a type-safe, fluent API that reduces template complexity and eliminates common errors. The primary use cases include building dynamic forms with automatic CSRF protection, creating reusable UI components through element immutability, and implementing model-backed forms that auto-populate from Eloquent models or session data. The package excels at handling form validation workflows where old input values need to be preserved after failed submissions, making it particularly valuable for CRUD operations and multi-step forms. Additional use cases include generating navigation menus, creating data tables with dynamic columns, building email templates, and constructing admin interfaces where form fields need consistent styling and behavior. The package integrates seamlessly with Laravel's ecosystem through automatic service provider registration, facade support, and a global `html()` helper function. Common integration patterns include using macros to define project-specific form components, combining with Blade components for encapsulating complex UI patterns, and leveraging the immutability pattern to create base element templates that can be safely reused across controllers and views. The builder works naturally with Laravel Collections, request validation, route helpers, and Eloquent model binding, making it a cohesive addition to any Laravel project. For team consistency, it's recommended to define standard form field macros in a service provider and use the builder throughout your Blade templates instead of raw HTML to maintain a single source of truth for element generation.