Blade Master Layouts: Components, Component Slots & View Composers

In modern web applications, repetitive UI patterns (buttons, modal dialogs, alert cards, form inputs, navigation menus) should never be duplicated across dozens of templates. Blade Components provide a React/Vue-like custom tag syntax (<x-alert>) directly inside PHP views, complete with attributes, props, and multi-slot layouts.

1. Building a Master Layout with <x-layout>

Create your master HTML shell inside resources/views/components/layout.blade.php:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{{ $title ?? 'Veewom Application' }}</title>
    @vite(['resources/css/app.css', 'resources/js/app.js'])
</head>
<body class="bg-gray-50 text-gray-900">
    <!-- Top Navigation -->
    <nav class="bg-white border-b px-6 py-4">
        <a href="/" class="font-bold text-xl text-red-900">Veewom</a>
    </nav>

    <!-- Optional Named Header Slot -->
    @isset($header)
        <header class="bg-white shadow-sm py-4 px-6 mb-6">
            {{ $header }}
        </header>
    @endisset

    <!-- Default Main Body Slot -->
    <main class="container mx-auto px-6 py-8">
        {{ $slot }}
    </main>
</body>
</html>

2. Consuming the Layout with Named Slots

Now, any view can consume this master layout by wrapping its content inside <x-layout>:

<x-layout title="User Dashboard - Veewom">
    <x-slot:header>
        <h1 class="text-2xl font-bold">Student & Developer Dashboard</h1>
    </x-slot:header>

    <div class="grid grid-cols-3 gap-6">
        <x-card title="Active Classes" count="50" />
        <x-card title="Completed Labs" count="15" />
        <x-card title="Interview Score" count="98%" />
    </div>
</x-layout>

3. Building Reusable UI Components with @props

Create an anonymous alert component in resources/views/components/alert.blade.php:

@props([
    'type' => 'info',
    'dismissible' => false
])

@php
$colorClasses = match($type) {
    'success' => 'bg-green-100 text-green-800 border-green-300',
    'danger'  => 'bg-red-100 text-red-800 border-red-300',
    'warning' => 'bg-yellow-100 text-yellow-800 border-yellow-300',
    default   => 'bg-blue-100 text-blue-800 border-blue-300',
};
@endphp

<div {{ $attributes->merge(['class' => "p-4 border rounded-md mb-4 {$colorClasses}"]) }} role="alert">
    <div class="flex items-center justify-between">
        <div>{{ $slot }}</div>
        @if ($dismissible)
            <button type="button" class="text-sm font-bold ml-4">×</button>
        @endif
    </div>
</div>

Consume it anywhere with custom HTML attributes merged automatically:

<x-alert type="danger" :dismissible="true" id="login-alert">
    <strong>Security Alert:</strong> Please verify your email address.
</x-alert>

4. View Composers (Sharing Data with All Views)

If you have data that must appear on every page (like category lists, user notifications, or shopping cart counts), do not query it in every controller. Register a View Composer in app/Providers/AppServiceProvider.php:

use Illuminate\Support\Facades\View;
use App\Models\Category;

public function boot(): void
{
    // Share $globalCategories with every view that renders the sidebar
    View::composer('partials.sidebar', function ($view) {
        $view->with('globalCategories', Category::withCount('articles')->get());
    });
}

Frequently Asked Questions (FAQ) - Student & Interview Review

Q1. What is the difference between $attributes and $props in Blade components?

@props defines expected custom PHP variables passed to the component. $attributes captures all standard HTML attributes (class, id, data-*, style) passed to the component tag.

Q2. What is the syntax difference between passing a string vs PHP variable to a component?

Strings are passed normally (title='My Title'). PHP expressions or booleans are prefixed with a colon (:count='$userCount' :dismissible='true').

Q3. How does View::share() differ from View::composer()?

View::share('key', $value) binds data globally to every view in the application on startup. View::composer('template', ...) executes lazily only when that specific template is actually rendered.

Explore Related Laravel Tutorials & Next Steps

Broaden your backend architecture, REST API design, and enterprise production engineering expertise:

Blade Syntax & Directives

Master loops, conditionals, and raw data escaping inside Blade templates.

Livewire 3 vs Inertia.js (Vue & React)

Elevate Blade layouts with reactive full-stack Livewire components.

Asset Bundling with Vite

Inject compiled JavaScript modules and stylesheet links into Blade master layouts.

15+ Hands-on Practice Labs

Build modular dashboard layouts and alert cards with component slots.

Share Share on Facebook Share on Twitter Share on LinkedIn Pin on Pinterest Share on Reddit

You may also like this!