Thinking in Components with Laravel 5.4 and Blade
How the @component directive introduced in Laravel 5.4's Blade templating engine lets you split views into reusable, well-defined pieces.
After working on a Laravel project for a while, you inevitably run into the same scene: dozens of Blade files, all carrying similar HTML blocks. You tweak something in one place and miss it somewhere else. The view layer, grown through copy-paste, becomes the most neglected corner of the application.
Laravel 5.4 addressed this with the @component directive. When I first saw it, my reaction was “we already have @include — what’s the difference?” The more I used it, though, the more that difference mattered.
The difference between @include and @component
@include pulls in a Blade file as-is; you pass data through a second array parameter, or the partial simply inherits all variables from the parent template. Fine for simple repetition.
@component introduces an actual component concept. Content is passed into the component via @slot, and the component places it using {{ $slot }}. You can also define named slots — a header, an action button, a footer — each going into its own distinct slot.
{{-- resources/views/components/card.blade.php --}}
<div class="card">
<div class="card-header">
{{ $header }}
</div>
<div class="card-body">
{{ $slot }}
</div>
</div>
Usage:
@component('components.card')
@slot('header')
User Information
@endslot
<p>Name: {{ $user->name }}</p>
<p>Email: {{ $user->email }}</p>
@endcomponent
Reading the template, it’s immediately clear what the structure looks like and where each piece goes. The HTML fragment is no longer just a “container” — it’s a small unit with a defined contract.
If you tried to do the same with @include, the partial would have access to every variable in the parent template, and it would quickly become ambiguous which variables “belong to the component” versus which ones “leaked in from the surrounding context.” @component draws that boundary clearly: the component knows only what it has been explicitly given.
Why this approach works
I saw the difference most clearly when I built an alert component for a real project. The application needs success, error, and info alert boxes in dozens of places. The color, icon, and styling are all the same — only the message and type change.
{{-- resources/views/components/alert.blade.php --}}
<div class="alert alert-{{ $type ?? 'info' }}">
{{ $slot }}
</div>
Now everywhere I just write:
@component('components.alert', ['type' => 'success'])
Your profile has been updated successfully.
@endcomponent
If the CSS class needs to change, I open one file. If I need to add a new type, again — one place. The maintenance burden genuinely shrinks.
The first time I tried this, I noticed something small but concrete: I never had to ask “I’m changing the alert box — how many places did I use it?” The component makes the question irrelevant.
Component or include?
You don’t need a component for everything. For simple, parameter-free partial views, @include is still the cleaner choice. But if an HTML block meets these conditions, moving it to a component makes sense:
- It’s used on more than one page.
- Its content comes from outside (variable text, an action).
- It looks different in different contexts (like a type parameter).
Asking these questions helped me slice the view layer more deliberately.
There’s also a trap in the opposite direction: componentizing everything. Creating a component for a single-use, parameter-free fragment just means opening a new file and adding an extra abstraction layer — it makes the code harder to read, not easier. Tying the component decision to “is this used in more than one place?” keeps that overengineering in check.
Seeds of a design system
A handful of well-named, documented components gradually form the nucleus of a small design system. Components like card, alert, modal, and form-group, once written well, almost automatically maintain the visual consistency of the application.
This habit also shifted how I read template files over time. When I look at a Blade file now, I no longer ask “what does this HTML do?” — I ask “how do these components fit together?” It’s a small mental shift, but it keeps the view layer maintainable for much longer.
I won’t claim this directive was a groundbreaking innovation — on the Vue side, the component model is far more powerful. But for server-side Blade templates, this has been the cleanest way I’ve found to gain reusability without adding unnecessary complexity.
Comments
Sign in with your GitHub account to join the discussion. Comments are stored in GitHub Discussions.