Blade Component Tricks Every Laravel Developer Should Know
Blade components are the cleanest way to build a reusable UI in Laravel, but a lot of developers stop at the basics and never touch the features that make them genuinely powerful. Here are the tricks that separate a tidy component library from a pile of copy-pasted partials.
Merge Classes Instead of Overwriting Them
The $attributes bag forwards any HTML attributes you pass to a component. The magic is merge(), which combines your default classes with whatever the caller provides instead of clobbering them:
{{-- resources/views/components/alert.blade.php --}}
<div {{ $attributes->merge(['class' => 'rounded p-4 border']) }}>
{{ $slot }}
</div>
<x-alert class="bg-red-100 text-red-800">
Something went wrong.
</x-alert>
The rendered element gets both the component defaults and the caller's classes. For conditional defaults, class() takes an array of class => boolean pairs:
<div {{ $attributes->class(['p-4', 'bg-red-100' => $type === 'error']) }}>
Declare Props With @props
Stop reading raw variables and start declaring what a component expects. @props documents the public API of a component and gives you default values in one line:
@props([
'type' => 'info',
'dismissible' => false,
])
<div {{ $attributes->class(['alert', "alert-{$type}"]) }}>
{{ $slot }}
@if ($dismissible)
<button type="button" data-dismiss>×</button>
@endif
</div>
Anything in @props becomes a variable; anything not in it stays in the attribute bag and forwards to the root element. That distinction is the whole mental model.
Use Named Slots for Structured Layouts
The default $slot is great, but real components often have a header, body, and footer. Named slots let callers fill specific regions:
{{-- components/card.blade.php --}}
<div class="card">
<div class="card-header">{{ $header }}</div>
<div class="card-body">{{ $slot }}</div>
@isset($footer)
<div class="card-footer">{{ $footer }}</div>
@endisset
</div>
<x-card>
<x-slot:header>Monthly Report</x-slot:header>
The body content goes here.
<x-slot:footer>Generated today</x-slot:footer>
</x-card>
Note the @isset guard — named slots are optional unless you make them required, so always check before rendering optional regions.
Reach for Inline Components When a File Feels Heavy
Not every component needs both a class and a view. For tiny presentational components, an anonymous component (just a Blade file in resources/views/components/) is all you need. And when even that is overkill, render a component inline straight from a class:
class Alert extends Component
{
public function __construct(public string $type = 'info') {}
public function render(): string
{
return <<<'blade'
<div class="alert alert-{{ $type }}">{{ $slot }}</div>
blade;
}
}
Pass PHP Objects, Not Just Strings
Prefix an attribute with : to pass a real PHP expression instead of a string. This is how you hand whole models or arrays to a component:
<x-user-card :user="$user" :roles="$user->roles" />
Inside the component, $user is the actual Eloquent model, not the string "$user". It is a small syntax detail that trips up newcomers constantly, and getting it right is the difference between a component that works and one that renders the literal text of your variable name.
Master these five and your Blade layer stops being a dumping ground for markup and starts being a real component system you can reason about.