tomjamon/laravel-custom-html
A Laravel package for managing and rendering custom HTML content in your applications. Define reusable HTML snippets, output them in Blade views, and keep custom markup organized with a simple, framework-friendly API.
Install via Composer
composer require tomjamon/laravel-custom-html
The package is a derivative of laravelcollective/html, so the mental model is the same: it provides a Html facade for link/meta/script generation and a Form facade for building forms.
Wire up the service provider and aliases
On Laravel 5.5+ package discovery should register the provider automatically. If it doesn't (or you're on an older version), add to config/app.php:
'providers' => [
Tomjamon\CustomHtml\CustomHtmlServiceProvider::class,
],
'aliases' => [
'Html' => Tomjamon\CustomHtml\Facades\HtmlFacade::class,
'Form' => Tomjamon\CustomHtml\Facades\FormFacade::class,
],
Check the actual class names in vendor/tomjamon/laravel-custom-html/src — this is a small, unmaintained fork, so namespaces may differ from the README.
Publish configuration (if the package ships one)
php artisan vendor:publish --provider="Tomjamon\CustomHtml\CustomHtmlServiceProvider"
First use case — a create form
{!! Form::open(['route' => 'posts.store', 'method' => 'POST']) !!}
{!! Form::label('title', 'Title') !!}
{!! Form::text('title', old('title'), ['class' => 'form-input']) !!}
{!! Form::submit('Save', ['class' => 'btn']) !!}
{!! Form::close() !!}
This emits the CSRF token, _method spoofing field, and standard markup automatically. That is the core value: you stop hand-writing form boilerplate in Blade.
Where to look first
laravelcollective/html.config/custom-html.php (if published) — any component/macro toggles.laravelcollective/html — the fork's "custom" additions are the reason to use it.Model binding with Form::model
The most common day-to-day pattern for edit screens:
{!! Form::model($post, ['route' => ['posts.update', $post], 'method' => 'PUT']) !!}
{!! Form::text('title') !!}
{!! Form::textarea('body') !!}
{!! Form::select('status', ['draft' => 'Draft', 'live' => 'Live']) !!}
{!! Form::close() !!}
Form::model auto-populates values from $post (including old() fallback on validation failure if Session is available), and close() flushes the internal model state — do not omit close().
Reusable fields via macros
Macros are the idiomatic extension point and the closest thing this package has to Blade components:
// AppServiceProvider::boot()
Form::macro('currency', function ($name, $value = null, $options = []) {
return Form::text($name, $value, array_merge($options, [
'step' => '0.01',
'class' => 'form-input currency',
]));
});
Then {!! Form::currency('price') !!} anywhere. Register macros in a boot method, not at file top-level, so config caching and queued/console contexts don't break.
Validation-friendly markup
Pair the package with @error / $errors in Blade, and let the builder render old() automatically. For custom error display, wrap fields:
<div class="field @error('email') has-error @enderror">
{!! Form::email('email') !!}
</div>
Html helpers for page chrome
Use the Html facade for meta/links in layouts rather than raw tags when you want consistency or central control over assets:
{!! Html::style('css/app.css') !!}
{!! Html::script('js/app.js') !!}
{!! Html::linkRoute('posts.show', 'View', [$post]) !!}
This is especially useful in packages/plugins where you can't hardcode asset paths.
Grouped/custom markup
For complex inputs (checkboxes, radios) use the array-of-options form:
{!! Form::select('roles[]', $roles, null, ['multiple' => true]) !!}
{!! Form::checkbox('terms', 1, false, ['id' => 'terms']) !!}
If the fork adds custom controls, look for dedicated methods in the source before hand-rolling markup.
Testing with these components
Because the builder renders strings, assert on rendered HTML in feature tests:
$this->get(route('posts.create'))
->assertSee('name="title"', false)
->assertSee('_token');
For unit tests of macros, call the facade directly: $this->assertEquals($expected, Form::currency('price'));.
{!! !!} for facade output. The builders return Illuminate\Support\HtmlString/strings deliberately unescaped. Wrap trusted builder calls in raw braces; never feed user content into an unescaped builder arg without escaping first._method are injected by open(). If you Form::open() and close with raw </form>, you lose them. Match with Form::close().composer dump-autoload and php artisan package:discover, and grep the src directory for the real provider/facade FQCNs.laravelcollective/html. Both register Html/Form aliases and macros; you'll get "class not found" or silently wrong macro resolution. Check composer show | grep -i html.Form::model but not close(), or render two models in one view. In tests, a forgotten close() produces confusing "wrong value" assertions.php artisan config:cache after adding macros/config changes. Macros defined outside boot methods won't exist in cached/queue processes.composer.json, and if you need Laravel 10/11+ support, verify the Illuminate version constraints in its composer.json before committing.dd(Form::text('x')->toHtml()) — most builders return a HtmlString, so you can inspect the exact output without a browser.spatie/laravel-html is actively maintained, and Laravel's native Blade components (<x-text-input>) remove a dependency entirely. Reach for this package only if you specifically need the laravelcollective/html API surface or the fork's custom macros, and prefer wrapping it behind your own small facade/helper layer so you can swap it out later.How can I help you explore Laravel packages today?