Laravel Blade Templating Reference

A reference for Laravel's Blade templating engine: directives, layouts, and components.

Layouts

A layout defines the shared page shell (nav, footer, scripts) once; individual views extend it and fill in named sections. This entire site's layouts.app works exactly this way.


{{-- resources/views/layouts/app.blade.php --}}
<body>
    @yield('content')
</body>

{{-- resources/views/posts/show.blade.php --}}
@extends('layouts.app')

@section('content')
    <h1>{{ $post->title }}</h1>
@endsection

Output and escaping


{{ $variable }}          {{-- HTML-escaped, safe for user input --}}
{!! $rawHtml !!}         {{-- NOT escaped, only for trusted HTML --}}
{{ $name ?? 'Guest' }}    {{-- with a default fallback --}}

Control structures


@if ($user->isAdmin())
    Admin
@elseif ($user->isEditor())
    Editor
@else
    Viewer
@endif

@foreach ($posts as $post)
    {{ $post->title }}
@endforeach

@forelse ($posts as $post)
    {{ $post->title }}
@empty
    No posts yet.
@endforelse

@auth
    Welcome back, {{ auth()->user()->name }}
@endauth

@guest
    <a href="/login">Log in</a>
@endguest

Including partials

An @include simply inlines another view's compiled output at that point in the template — it shares the including view's variable scope automatically, which is convenient but also means a typo'd variable name silently falls through to $undefinedVariable ?? null issues rather than an error. Repeating an include inside a loop compiles and evaluates it fresh every iteration, which is fine for small partials but worth remembering if the partial does anything expensive.


@include('partials.alert')

@include('partials.alert', ['type' => 'success'])

@includeWhen($errors->any(), 'partials.error-summary')

Use @once to guard a block so it only renders on the first pass through a given render cycle — handy when a component or partial that's included many times on one page needs to push a shared script or style tag exactly once:


@once
    @push('scripts')
        <script src="/js/tooltip.js"></script>
    @endpush
@endonce

Forms


<form method="POST" action="/posts">
    @csrf
    <input type="text" name="title">
    @error('title')
        <span class="text-danger">{{ $message }}</span>
    @enderror
</form>

{{-- Spoof PUT/PATCH/DELETE, since HTML forms only support GET/POST --}}
<form method="POST" action="/posts/1">
    @csrf
    @method('PUT')
</form>

Components

Reusable pieces of markup with their own data and, optionally, a backing class.

php artisan make:component Alert

{{-- resources/views/components/alert.blade.php --}}
<div class="alert alert-{{ $type }}">
    {{ $slot }}
</div>

{{-- usage --}}
<x-alert type="danger">
    Something went wrong.
</x-alert>
class Alert extends Component
{
    public function __construct(
        public string $type = 'info',
    ) {}

    public function render(): View
    {
        return view('components.alert');
    }
}

Declare expected props explicitly with @props in an anonymous (class-less) component:


{{-- resources/views/components/alert.blade.php --}}
@props(['type' => 'info'])

<div {{ $attributes->merge(['class' => "alert alert-$type"]) }}>
    {{ $slot }}
</div>

Components differ from includes in a few important ways: props are declared explicitly rather than inherited implicitly from the caller's scope, they can carry a backing class with real logic and dependency injection, and Blade compiles each one as a distinct object rather than re-inlining a template string. Reach for a component when the piece of UI has its own data or behaviour worth naming; reach for an include when you're just splitting a large view into smaller files that still share the same variables. Named slots let a component accept more than one block of markup:


{{-- 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:title>Account Settings</x-slot:title>
    Your default slot content goes here.
</x-card>

Conditional classes and attributes

The @class directive builds a class string from an array, applying each key only when its value is truthy — clearer than concatenating strings with ternaries, and it plays nicely with $attributes->merge() on components.


<div @@class([
    'alert',
    'alert-danger' => $errors->any(),
    'alert-success' => ! $errors->any(),
])>

A similar @checked, @selected, @disabled, and @readonly family of directives conditionally prints the matching HTML attribute, which is a common need on form re-renders after a failed validation.

Stacks

Let a child view push content (usually scripts or styles) up into a placeholder defined in the layout — used throughout this site's own tool pages for per-page <style>/<script> blocks.


{{-- layout --}}
@stack('scripts')

{{-- child view --}}
@push('scripts')
    <script>console.log('hi');</script>
@endpush

Compilation and caching

Blade templates aren't interpreted directive-by-directive on every request. The first time a view is rendered, Laravel compiles it down to plain PHP and writes the result to storage/framework/views; every subsequent request just runs that cached PHP file directly, so the templating layer adds effectively no runtime overhead once warmed. Laravel checks the compiled file's timestamp against the source .blade.php file and recompiles automatically whenever the source changes, so this is invisible during normal development.

The one place it does bite is production deploys behind a cache that was primed against an old copy of the code — if the compiled cache directory isn't cleared as part of the deploy, stale views can serve briefly. php artisan view:clear deletes the compiled files, and php artisan view:cache pre-compiles every view up front so the very first request after a deploy isn't the one paying the compilation cost.

php artisan view:clear
php artisan view:cache