Blade Components
Creating reusable components in Blade
Blade Components allow you to create reusable components that can be used in different views. This pattern makes code modular and maintainable.
Types of Blade Components:
1. Anonymous Components: Components without class that only have view file. Simpler and faster for simple components.
2. Class-based Components: Class-based components with logic and data manipulation. For more complex components.
Benefits of Components:
- Reusability across multiple views
- Cleaner and more organized code
- Better management of UI elements
- Props for passing data
- Slots for dynamic content
- Attributes merging for HTML attributes
- Event handling
- State management
Advanced Features:
- <strong>Props</strong>: Receiving data from parent
- <strong>Slots</strong>: Dynamic content
- <strong>Named Slots</strong>: Multiple slots with different names
- <strong>Attributes</strong>: HTML attributes merging
- <strong>Events</strong>: Event handling
- <strong>Computed Properties</strong>: Computing properties
- <strong>Lifecycle Hooks</strong>: Hooks for component lifecycle
Examples
Anonymous Component
<!-- resources/views/components/alert.blade.php -->
<div class="alert alert-{{ $type }}">
{{ $message }}
</div>
<!-- Usage -->
<x-alert type="error" message="Something went wrong!" />
<!-- With default props -->
<!-- In component -->
@props(['type' => 'info', 'message' => ''])
<div class="alert alert-{{ $type }}">
{{ $message }}
</div>
Using an anonymous component with props.
Class-based Component
<?php
namespace App\View\Components;
use Illuminate\View\Component;
class Alert extends Component
{
public function __construct(
public string $type = 'info',
public string $message = '',
public bool $dismissible = false
) {}
public function render()
{
return view('components.alert');
}
public function alertClass(): string
{
return match($this->type) {
'error' => 'alert-danger',
'success' => 'alert-success',
'warning' => 'alert-warning',
default => 'alert-info'
};
}
}
<!-- Usage -->
<x-alert type="error" message="Error occurred" :dismissible="true" />
Creating a class-based component.
Component with Slots
<!-- resources/views/components/card.blade.php -->
<div class="card">
@if(isset($header))
<div class="card-header">
{{ $header }}
</div>
@endif
<div class="card-body">
{{ $slot }}
</div>
@if(isset($footer))
<div class="card-footer">
{{ $footer }}
</div>
@endif
</div>
<!-- Usage -->
<x-card>
<x-slot name="header">
<h2>Card Title</h2>
</x-slot>
Card content here
<x-slot name="footer">
<button>Action</button>
</x-slot>
</x-card>
Using slots for dynamic content.
Attributes Merging
<!-- resources/views/components/button.blade.php -->
@props(['type' => 'button', 'variant' => 'primary'])
<button
type="{{ $type }}"
{{ $attributes->merge(['class' => 'btn btn-' . $variant]) }}
>
{{ $slot }}
</button>
<!-- Usage -->
<x-button variant="danger" class="custom-class" id="submit-btn">
Submit
</x-button>
<!-- Renders: -->
<!-- <button type="button" class="btn btn-danger custom-class" id="submit-btn">Submit</button> -->
Attributes merging for HTML attributes.
Component with Data
<?php
namespace App\View\Components;
use Illuminate\View\Component;
class UserList extends Component
{
public function __construct(
public $users,
public bool $showEmail = true
) {}
public function userCount(): int
{
return $this->users->count();
}
public function render()
{
return view('components.user-list');
}
}
<!-- Usage -->
<x-user-list :users="$users" :show-email="false" />
Component with data and computed properties.
Inline Components
<?php
namespace App\View\Components;
use Illuminate\View\Component;
class Alert extends Component
{
public function __construct(
public string $type,
public string $message
) {}
public function render()
{
return <<<'blade'
<div class="alert alert-{{ $type }}">
{{ $message }}
</div>
blade;
}
}
Inline component that doesn't have view file.
Component Namespaces
<?php
// In AppServiceProvider
use Illuminate\Support\Facades\Blade;
Blade::componentNamespace('App\View\Components\Forms', 'forms');
// Usage
<x-forms::input name="email" type="email" />
// Or in package
Blade::componentNamespace('Vendor\Package\View\Components', 'package');
// Usage
<x-package::component />
Component namespaces for better organization.
Dynamic Components
<!-- Dynamic component selection -->
<x-dynamic-component :component="$componentName" :data="$data" />
<!-- Example -->
@php
$componentName = 'alert';
$data = ['type' => 'error', 'message' => 'Error!'];
@endphp
<x-dynamic-component :component="$componentName" :type="$data['type']" :message="$data['message']" />
Dynamic component selection based on variable.
Use Cases
- Creating reusable UI elements
- Organizing view code
- Creating design system components
- Reducing code duplication
- Managing complex UI logic
- Creating component library
Common Mistakes
- Using class-based component for simple components
- Not using props causing hard-coding
- Forgetting attributes merging
- Putting business logic in component
- Not using slots for flexibility
- Component namespaces causing confusion
Best Practices
- Use anonymous components for simple components
- Use class-based components for complex logic
- Use props for data passing
- Use slots for dynamic content
- Use attributes merging for HTML attributes
- Choose descriptive component names
- Test components
Edge Cases
- Nested components with complex data flow
- Components with conditional rendering
- Dynamic component selection
- Components with event handling
- Component caching in production
- Components with very large props
Performance Notes
- Anonymous components are faster than class-based
- Component compilation is cached
- Using inline components can have overhead
- Nested components can be slow
- Component caching in production improves performance
Security Notes
- Ensure props are properly escaped
- Use raw output in components with caution
- Ensure user input in props is validated
- Use component namespaces for isolation
Interview Points
- What is the difference between anonymous and class-based component?
- What are props and how do they work?
- What are slots and when are they used?
- How does attributes merging work?
- How can you define component namespace?
- What are the benefits of using Blade components?
Version Notes
- Laravel 11.x: Improved performance in component rendering
- Laravel 11.x: Better support for attributes merging
- Laravel 10.x: Improved anonymous components
- Laravel 9.x: Improved component namespaces