Blade: Layouts & Components
The previous lesson covered Blade's basic directives — {{ }} for escaped output,
@if/@foreach for control structures, and the general idea that Blade
compiles down to plain PHP. This lesson builds on that foundation with the features that make
Blade genuinely useful for building real applications: layouts so you don't
repeat your `<html>`, header, and footer on every single page, and components
so you don't repeat little pieces of UI (alerts, cards, form fields) either. Both are about one
idea — Don't Repeat Yourself — applied to your views instead of your PHP logic.
Template Inheritance: @extends and @section
Instead of every view being a complete, self-contained HTML document, you define one master
layout that holds the shared skeleton (the <head>, navigation, footer),
with a placeholder marking where page-specific content should go. Individual views then
extend that layout and only supply the content for the placeholder. The
placeholder is declared in the layout with @yield('name'), and a child view fills it
using @section('name') ... @endsection.
Example: A Master Layout
<!-- resources/views/layouts/app.blade.php -->
<!DOCTYPE html>
<html>
<head>
<title>@yield('title', 'My App')</title>
</head>
<body>
<nav>Site navigation goes here</nav>
<main>
@yield('content')
</main>
<footer>© 2026 My App</footer>
</body>
</html>
Example: A Child View Extending the Layout
<!-- resources/views/articles/show.blade.php -->
@extends('layouts.app')
@section('title', $article->title)
@section('content')
<h1>{{ $article->title }}</h1>
<p>{{ $article->body }}</p>
@endsection
Notice that show.blade.php no longer contains any <html> or
<body> tags at all — it only supplies the two sections the layout expects.
When this view is rendered, Blade takes layouts/app.blade.php, and wherever it finds
@yield('content'), it drops in whatever was defined inside
@section('content') ... @endsection in the child view. The optional second argument to
@yield('title', 'My App') is a default value used if the child view never defines that
section — handy so every page doesn't have to set a title.
resources/views/layouts/, and the dot notation in @extends('layouts.app') maps directly to that folder path — dots become slashes, and .blade.php is assumed.Blade Components: Reusable UI Pieces
Layouts solve repetition at the whole-page level. Components solve it at the smaller, reusable-widget level — an alert box, a card, a form input with a label and error message, a modal — anything you'd otherwise copy-paste across several views. A component is generated with Artisan and consists of two halves: a small PHP class (optional, for logic) and a Blade view (the markup).
Example: Generating and Defining a Component
# From your project's terminal
php artisan make:component Alert
This creates two files:
app/View/Components/Alert.php— the component's classresources/views/components/alert.blade.php— the component's markup
<?php
// app/View/Components/Alert.php
namespace App\View\Components;
use Illuminate\View\Component;
class Alert extends Component
{
public $type;
public function __construct($type = 'info')
{
$this->type = $type;
}
public function render()
{
return view('components.alert');
}
}
<!-- resources/views/components/alert.blade.php -->
<div class="alert alert-{{ $type }}">
{{ $slot }}
</div>
Using the component anywhere in the application looks like a plain HTML tag:
<x-alert type="error">Something went wrong</x-alert>
Passing Data and Using the Slot
The constructor argument $type automatically becomes available to the component's
view as a variable — that's what makes type="error" in the tag turn into
$type equal to "error" inside alert.blade.php. Any attribute
you put on the <x-alert> tag that matches a constructor parameter is passed
through automatically; Laravel wires this up for you.
The content placed between the opening and closing tags — Something went wrong
in the example above — is captured automatically into a special variable called
$slot. Printing {{ $slot }} inside the component's view is what renders
that inner content. This is what makes components genuinely flexible: the caller controls the
inner content, the component controls the wrapping markup and styling.
<x-slot name="...">) for more advanced layouts, such as a card component with a separate header and body — but the single default $slot covers the large majority of everyday cases.Anonymous Components
Not every component needs a PHP class behind it. If a component is purely markup with no
constructor logic to run, you can skip the class entirely and just create a Blade file directly
inside resources/views/components/. Laravel automatically treats any file placed
there as a usable <x-*> component, even without a matching class.
Example: An Anonymous Alert Component
<!-- resources/views/components/alert.blade.php (no class needed) -->
@props(['type' => 'info'])
<div class="alert alert-{{ $type }}">
{{ $slot }}
</div>
The @props directive at the top declares which attributes count as component
"props" (with optional defaults) versus which should just be passed through as plain HTML
attributes. It's the anonymous-component equivalent of the constructor arguments in the
class-based version, and it's used exactly the same way from the calling view:
<x-alert type="error">Something went wrong</x-alert>. For components that
are simple presentation with no PHP logic to run, anonymous components mean one less file to
maintain.
Including Sub-Views with @include
Before components existed, and still very commonly today for simpler cases, Blade offers
@include to pull in another view's markup inline. It's a more basic tool than a
component — no props system, no slots — it simply drops the included view's compiled output at
that point, with access to whatever variables are already in scope.
<!-- resources/views/layouts/app.blade.php -->
<body>
@include('partials.header')
@yield('content')
@include('partials.footer')
</body>
Reach for @include for small, static fragments (a header, a footer, a repeated
sidebar block); reach for a full component when the piece of UI needs its own logic, props, or is
reused with varying data across many different pages.
Stacks: @push and @stack
Here's a genuinely useful, less obvious feature: sometimes one specific child view needs to add
its own <script> or <style> tag, but only the layout controls
where the closing </body> tag is. Copy-pasting the whole layout just to add one
script tag would defeat the purpose of having a shared layout at all. Stacks solve
this: the layout declares a named "stack" as a slot for content, and any child view can
@push content onto that named stack from anywhere, even though the actual output
location is fixed by the layout.
Example: Page-Specific Scripts via a Stack
<!-- resources/views/layouts/app.blade.php -->
<body>
@yield('content')
<script src="/js/app.js"></script>
@stack('scripts')
</body>
<!-- resources/views/articles/show.blade.php -->
@extends('layouts.app')
@section('content')
<h1>{{ $article->title }}</h1>
@endsection
@push('scripts')
<script src="/js/article-comments.js"></script>
@endpush
Only the show.blade.php view for an article page pushes
article-comments.js, but the actual <script> tag ends up printed
wherever @stack('scripts') was declared in the layout — right after the shared
app.js, in the right place, without touching the layout file at all. Views that don't
push anything to that stack simply render nothing extra there.
| Feature | Use it for |
|---|---|
@extends / @yield | Sharing the overall page skeleton across many views |
| Class-based component | Reusable UI that needs PHP logic behind it |
| Anonymous component | Reusable UI that's markup-only, no logic needed |
@include | Simple, static fragments reused across views |
@push / @stack | Letting a specific view inject content into a fixed spot in the layout |