# 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'));
//
// 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');
//
```
### 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.