Laravel Magazine

Blade Component Tricks Every Laravel Developer Should Know

Eric Van Johnson · Tips
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>&times;</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.

Stay Updated

Subscribe to our newsletter

Get latest news, tutorials, community articles and podcast episodes delivered to your inbox.

Weekly articles
We send a new issue of the newsletter every week on Friday.
No spam
We'll never share your email address and you can opt out at any time.