skip to content

In a Blade @extends layout, how do @section, @parent, @show, @endsection and @yield decide whether a child replaces or extends layout content?

level: middleimportance: should knowfreq 38%

answer

  1. the child's section is stored first
  2. @endsection stores, @show stores and prints
  3. @parent is a placeholder for the layout's content
  4. @overwrite replaces, @append concatenates
  5. @yield default is escaped

basics

~20 s

The child renders first, so its section is stored first and wins. A layout default written as @section ... @show only survives where the child wrote @parent, which is a placeholder for it. @endsection only stores; @show and @yield print.

solid answer

~40 s

Blade compiles `@extends` into a footer call, so the child executes before the layout. `@section('sidebar') ... @endsection` in the child stores the content in the view factory without printing it. When the layout then reaches `@section('sidebar') default @show`, Blade merges into the stored entry instead of replacing it: the layout's default text only replaces a `@parent` placeholder, so without `@parent` the child's version stands alone. `@show` ends the section *and* prints it; `@yield('sidebar', 'fallback')` just prints what is stored, or the escaped fallback. `@overwrite` ends a section by replacing whatever was stored, and `@append` concatenates. Two traps: the one-line `@section('title', $name)` escapes its value, and markup a child writes outside any section is printed before the layout's HTML.

code

html · 19 lines
html
<!-- resources/views/layouts/app.blade.php -->
<aside>
    @section('sidebar')
        <a href="/faculties">Faculties</a>
    @show
</aside>
<main>@yield('content')</main>

<!-- resources/views/events/open-day.blade.php -->
@extends('layouts.app')

@section('sidebar')
    @parent
    <p>Open day on Saturday</p>
@endsection

@section('content')
    <h1>Open day</h1>
@endsection

go deeper

for a junior

Recall the verbs: @section ... @endsection stores, @show stores and prints, @yield prints, @parent keeps the layout's version inside the child's.

for a middle

Explain why the child wins: @extends renders the layout in the child's footer, and ending a section only replaces the @parent placeholder in what was already stored.

for a senior

Diagnose layout bugs from the mechanism: a sidebar default that vanished, a debug line above the doctype, a double-escaped title from the one-line section form.

for a principal

Weigh how much section plumbing a layout should expose; many named regions with @parent chains become hard to reason about, which is one reason teams move shells to components.

## The render order behind every section rule In Blade's **template inheritance**, a child view names its parent with `@extends('layouts.app')`. The compiler does not print anything at that spot: it appends a line to the **footer** of the compiled child that renders the layout. The consequence drives every rule below: 1. The child's compiled code runs first. 2. Each `@section ... @endsection` it contains is captured with output buffering and **stored** in the shared view factory under its name. 3. Only then does the layout render, printing stored sections where it asks for them. So when a section name appears in both files, the **child's content is already stored** by the time the layout's definition runs. ## What each directive does | Directive | Effect | |---|---| | `@section('name') ... @endsection` | capture and store the content, print nothing | | `@stop` | same as `@endsection` | | `@section('name') ... @show` | capture, merge into the stored entry, then print it immediately | | `@yield('name', 'default')` | print the stored content, or the default when nothing is stored | | `@parent` | a placeholder, later replaced by the layout's own content for that section | | `@append` | end the section by concatenating onto what is stored | | `@overwrite` | end the section by replacing what is stored | | `@section('name', 'value')` | one-line form: store the value, escaped | ## Replace or extend: the merge rule When a section ends normally (`@endsection`, `@stop` or `@show`), Blade does not simply overwrite. If something is already stored under that name, it **replaces only the `@parent` placeholder inside the stored content** with the new content, and keeps the stored content otherwise. Walk through a university layout: - The layout has `@section('sidebar') <a href="/faculties">Faculties</a> @show`. - A child writes `@section('sidebar') <p>Open day on Saturday</p> @endsection`. - The child runs first, so the stored sidebar is the open-day paragraph. - The layout's `@show` merges its link in, but the stored text has no placeholder, so nothing changes: the sidebar prints **only** the open-day paragraph. If the child instead writes `@parent` above its paragraph, the stored text is "placeholder + paragraph". The layout's merge swaps its faculty link into the placeholder, so the sidebar prints the **link first, then the paragraph**. Put `@parent` below the paragraph and the order flips. Two refinements: - `@parent` only has something to insert when the layout defines the section with `@section ... @show`. If the layout prints the region with a bare `@yield('sidebar', 'default')`, there is no layout content to merge; the placeholder is stripped when the section is printed, and the `@yield` default is not substituted, because the section is set. - `@overwrite` skips the merge entirely and stores the new content, and `@append` glues the new content onto the end of what is stored. Both are rare; most code needs only `@endsection`, `@show`, `@yield` and `@parent`. ## Multi-level layouts The same rules chain through more than two levels. Suppose a course page extends `layouts.department`, which itself extends `layouts.app`: 1. The course page runs and stores its `sidebar`, which starts with `@parent`. 2. Its footer renders `layouts.department`, whose own `sidebar` section also starts with `@parent`; ending it replaces the course page's placeholder with the department's content, which still carries a placeholder of its own. 3. That layout's footer renders `layouts.app`, whose `@section('sidebar') ... @show` fills the last placeholder and prints the result. The sidebar then reads site links, department links, course note, from the most general level to the most specific. Drop `@parent` at any level and everything above that level disappears from the region. ## Escaping and defaults The two short forms escape their string argument with Blade's `e()` helper: - `@section('title', $course->name)` stores the escaped value, so a course name containing `<` prints safely. - `@yield('title', 'University')` escapes its string default. A block section is not escaped as a whole: it holds whatever its own `{{ }}` echoes produced. ## Checking whether a section exists A layout can branch on a section with `@hasSection('sidebar') ... @endif` or `@sectionMissing('sidebar') ... @endif`. These compile to a check that the section's printed content, trimmed, is not empty, so a section that contains only whitespace counts as missing. ## Markup outside sections Because the child's code runs top to bottom before the footer renders the layout, any markup a child writes **outside** every `@section` is printed immediately, which puts it **before the layout's `<html>`**. A stray line of text or a debug dump at the top of a child therefore appears above the doctype. It is not silently dropped. Keep every piece of a child view inside a section.

  • Why does a Blade child's section beat the layout's @section ... @show default even though the layout's code runs later?
    Ending a section merges rather than overwrites. The view factory looks for the `@parent` placeholder inside the content already stored under that name and replaces only the placeholder with the new content. The child stored its version first, so without a placeholder the layout's default has nowhere to go. `@overwrite` is the directive that forces a real replacement.
  • What does @hasSection('sidebar') treat as missing in a Blade layout?
    It compiles to a check that the yielded section content, trimmed, is not empty. A section that was never defined and a section defined with only whitespace both count as missing, so `@sectionMissing('sidebar')` is true for both. That lets a layout skip the whole `<aside>` wrapper when a page has nothing to say there.

saying these in an interview costs you the question

  • The layout's @section ... @show default overrides the child because the layout runs last
  • @endsection prints the section at the place where it is written
  • @parent inserts the default text given to @yield('name', 'default')
  • Markup a child writes outside any @section is silently discarded
  • The one-line @section('title', $name) form prints the value unescaped