Blade Components

Creating reusable components in Blade

graph TD A[Component Usage] --> B{Type?} B -->|Anonymous| C[View File Only] B -->|Class-based| D[Component Class] D --> E[View File] C --> F[Render] E --> F G[Props] --> C G --> D H[Slots] --> C H --> D

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