Blade components are reusable UI elements that help you build consistent, maintainable interfaces in Laravel. They come in two main types: class-based components with associated logic and anonymous components for simple reusable snippets. This guide will walk you through creating and using both types effectively.
What Are Blade Components?
Blade components are a powerful feature of Laravel's Blade templating engine that allow you to create custom, reusable HTML and PHP snippets . They follow a component-based architecture similar to modern JavaScript frameworks but work seamlessly within Laravel's ecosystem.
Key Benefits:
- Code Reusability: Write once, use anywhere in your application
- Encapsulation: Keep logic and presentation organized together
- Maintainability: Update in one place, changes propagate everywhere
- Consistency: Ensure uniform UI elements across your application
Creating Your First Class-Based Component
Class-based components consist of a PHP class for logic and a Blade view for presentation.
Step 1: Generate the Component
Use Laravel's Artisan command to create a component:
php artisan make:component Alert
This command generates two files :
- app/View/Components/Alert.php (the component class)
- resources/views/components/alert.blade.php (the Blade template)
Step 2: Define the Component Class
Open app/View/Components/Alert.php
and define your component's logic:
namespace App\View\Components;
use Illuminate\View\Component;
class Alert extends Component
{
public $type;
public $message;
public function __construct($type, $message)
{
$this->type = $type;
$this->message = $message;
}
public function render()
{
return view('components.alert');
}
}
The constructor accepts parameters that will be passed when using the component
Step 3: Create the Blade Template
Edit resources/views/components/alert.blade.php
:
<div class="alert alert-{{ $type }}">
{{ $message }}
</div>
This template uses the $type
and $message
variables defined in the component class.
Step 4: Use the Component
Use your new component in any Blade template with the x-
prefix:
<x-alert type="success" message="Operation completed successfully!" />
<x-alert type="error" :message="$errorMessage" />
Prefix attributes with :
when passing variables instead of static strings.
Creating Anonymous Components
Anonymous components are perfect for simple components that don't require separate class logic.
Step 1: Generate the Component
php artisan make:component alert --view
This creates only the Blade template: resources/views/components/alert.blade.php
.
Step 2: Define Props with @props
For anonymous components, use the @props directive to declare expected variables:
@props([
'type' => 'info', // Default value
'message'
])
<div class="alert alert-{{ $type }}">
{{ $message }}
</div>
Step 3: Use the Anonymous Component
Usage is identical to class-based components:
<x-alert type="success" message="This is an anonymous component!" />
Working with Slots
Slots allow you to pass content between component tags instead of just attributes.
Default Slot
<!-- Component template -->
<div class="card">
{{ $slot }}
</div>
<!-- Usage -->
<x-card>
<p>This content goes into the $slot variable</p>
</x-card>
Named Slots
For multiple content sections, use named slots:
<!-- Component template (resources/views/components/card.blade.php) -->
<div class="card">
<div class="card-header">
{{ $title }}
</div>
<div class="card-body">
{{ $slot }}
</div>
</div>
<!-- Usage -->
<x-card>
<x-slot name="title">
Card Title
</x-slot>
This content goes into the default $slot.
</x-card>
Managing Component Attributes
The $attributes
variable provides access to all attributes passed to your component, allowing you to manage HTML attributes efficiently.
Passing Attributes to Root Element
<!-- Component template -->
<div {{ $attributes }}>
{{ $slot }}
</div>
<!-- Usage -->
<x-alert class="mt-4" id="main-alert">
Content here
</x-alert>
Merging Classes
<div {{ $attributes->merge(['class' => 'alert alert-'.$type]) }}>
{{ $slot }}
</div>
This merges passed classes with the component's default classes.
Advanced Component Features
The @aware
Directive
Child components can access data from parent components using @aware
:
<!-- Input component that's aware of parent's error state -->
@aware(['error'])
<input {{ $attributes->class([
'standard-classes',
'border-red-500' => $error
]) }} />
Layout Components
Create application-wide layouts using components:
<!-- resources/views/components/layouts/app.blade.php -->
<!DOCTYPE html>
<html>
<head>
<title>{{ $title ?? 'Default Title' }}</title>
</head>
<body>
<header><!-- Navigation --></header>
<main>
{{ $slot }}
</main>
<footer><!-- Footer content --></footer>
</body>
</html>
<!-- Usage in pages -->
<x-layouts.app title="Home Page">
<p>Page content here</p>
</x-layouts.app>
Practical Example: Building a Form Input Component
Here's a complete example of a form input component with label, error handling, and validation:
Input Group Component
<!-- resources/views/components/input/group.blade.php -->
@props([
'label',
'for',
'help',
'error',
])
<label {{ $attributes->class(['block']) }} for="{{ $for }}">
<span @class([
'text-gray-700 inline-block mb-1',
'text-red-500' => isset($error)
])>{{ $label }}</span>
<div class="mt-1">
{{ $slot }}
</div>
@isset($help)
<p class="mt-2 text-sm text-gray-500">{{ $help }}</p>
@endif
@isset($error)
<div class="mt-1 text-red-500 text-sm">{{ $error }}</div>
@endif
</label>
Text Input Component
<!-- resources/views/components/input/text.blade.php -->
@aware(['error'])
@props(['name', 'value'])
<input
{{ $attributes->class([
'shadow-sm focus:ring-indigo-500 focus:border-indigo-500 block w-full sm:text-sm border-gray-300 rounded-md',
'border-red-500' => $error
]) }}
name="{{ $name }}"
value="{{ $value }}"
{{ $attributes }}
/>
Usage in Forms
<x-form :action="route('users.store')">
<x-input.group label="Email" for="email" :error="$errors->first('email')">
<x-input.text name="email" :value="old('email')" />
</x-input.group>
<x-button.primary type="submit">
Submit
</x-button.primary>
</x-form>
Best Practices and Tips
- Use descriptive names that reflect the component's purpose
- Set sensible defaults for optional properties
- Leverage attribute merging for flexibility
- Use slots for complex content, attributes for simple data
- Group related components in subdirectories (e.g.,
form/
,modal/
) - Keep components focused on a single responsibility
Conclusion
Blade components significantly improve Laravel development by promoting code reuse, consistency, and maintainability. Whether you choose class-based components for complex logic or anonymous components for simple UI elements, you'll find they make your templating more organized and efficient.
Start by identifying repetitive UI patterns in your application and converting them into components. As you become more comfortable with the syntax, you can build sophisticated component libraries that accelerate your development workflow.