Creating Blade Components in Laravel: A Complete Tutorial

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.

Copyright © 2025 Akhmad.dev