skip to content

In Blade, how do @include, @includeIf, @includeWhen, @includeFirst, @includeIsolated and @each differ, especially in which variables the included view can see?

level: middleimportance: should knowfreq 50%

answer

  1. @include passes get_defined_vars()
  2. missing view: @include throws, @includeIf skips
  3. When/Unless take a boolean first
  4. @includeIsolated: only what you pass
  5. @each: item, key and an empty view

basics

~20 s

@include and its If, When, Unless and First variants hand the partial every parent variable plus extras, differing only in when they render; @includeIsolated passes just the given array, and @each renders a view per item with only that item and its key.

solid answer

~30 s

`@include('plans.card', ['highlight' => true])` compiles to `$__env->make(...)` with `get_defined_vars()` merged in, so the partial sees every local variable of the parent - including `$loop` - plus the extras. `@include` of a missing view throws; `@includeIf` checks `exists()` first. `@includeWhen($cond, 'view', [...])` and `@includeUnless` add a condition. `@includeFirst(['plans.custom', 'plans.card'])` renders the first view that exists, which suits overridable partials. `@includeIsolated('view', [...])` gives the partial only the array you pass. `@each('plans.card', $plans, 'plan', 'plans.none')` renders the view once per item with just `$plan` and `$key`, or the empty view. Data shared with `View::share` stays visible in all of them.

code

html · 12 lines
html
@foreach ($plans as $plan)
    {{-- sees $plan, $loop, $currentPlan and everything else in scope --}}
    @include('plans.card', ['highlight' => $plan->is($currentPlan)])
@endforeach

{{-- sees only plan and current --}}
@includeIsolated('plans.card', ['plan' => $featured, 'current' => $currentPlan])

@includeWhen($showComparison, 'plans.comparison')
@includeFirst(['clients.acme.plan-card', 'plans.card'], ['plan' => $featured])

@each('plans.feature-row', $featured->features, 'feature', 'raw|<li>No features listed</li>')

go deeper

for a junior

Recall that @include inherits the parent's variables and throws on a missing view, while @includeIf and @includeWhen add conditions.

for a middle

Explain the get_defined_vars() merge behind @include, what @includeIsolated and @each pass instead, and that shared view data reaches all of them.

for a senior

Choose isolation deliberately to keep partials decoupled, avoid @includeIf hiding typos, and know when a component with props replaces an include.

for a principal

Set a team convention for partials versus components so view inputs stay explicit and refactors do not silently break templates.

## What an include is An **include** renders another Blade view in place and inserts its HTML. Laravel offers a family of include directives; they differ in two ways: **when** the partial renders, and **which variables** it receives. ## The directives side by side | Directive | Renders when | Variables the partial sees | |---|---|---| | `@include('v', [...])` | always; throws if `v` is missing | all parent locals + the array | | `@includeIf('v', [...])` | only if `v` exists | all parent locals + the array | | `@includeWhen($c, 'v', [...])` | if `$c` is truthy | all parent locals + the array | | `@includeUnless($c, 'v', [...])` | if `$c` is falsy | all parent locals + the array | | `@includeFirst(['a', 'b'], [...])` | first existing view in the list | all parent locals + the array | | `@includeIsolated('v', [...])` | always | **only** the array | | `@each('v', $items, 'item', 'empty')` | once per item, or the empty view | **only** `$item` and `$key` | In every case, data registered globally with `View::share` (or by a view composer) is merged in by the view factory, so it is visible even to `@includeIsolated` and `@each`. ## How @include passes variables `@include` compiles to roughly: ```php <?php echo $__env->make('plans.card', ['highlight' => true], array_diff_key(get_defined_vars(), ['__data' => 1, '__path' => 1]))->render(); ?> ``` `get_defined_vars()` captures **every local variable** in the compiled parent at that point - view data, variables set with `@php`, the current `$loop` inside a `@foreach`, even `$__env`. The explicit array is merged on top, so its keys win. That is convenient and also the main design cost: the partial silently depends on whatever names the parent happens to define. Rename `$plan` to `$tier` in the parent and the partial breaks without any error at the include site. ## @includeIsolated and @each: explicit inputs `@includeIsolated('plans.card', ['plan' => $plan])` compiles to `$__env->make('plans.card', ['plan' => $plan])` with no `get_defined_vars()`. The partial receives exactly what you pass, which makes its inputs visible at the call site and stops accidental coupling. In the pinned Laravel 13 release it sits beside `@include` in the compiler and the Blade docs; check an older application's framework version before relying on it. `@each('plans.card', $plans, 'plan', 'plans.none')` loops for you. Each render gets `['key' => $key, 'plan' => $value]` and nothing from the parent. When `$plans` has no items it renders the fourth-argument view - or, if that argument starts with `raw|`, the literal text after the prefix. The docs call out the consequence: if the partial needs parent variables, use `@foreach` with `@include` instead. ## Picking one for a pricing table A plans page renders a card per tier, a comparison partial for logged-in visitors, and allows a white-label client to override the card: 1. `@includeFirst(['clients.acme.plan-card', 'plans.card'], ['plan' => $plan])` - use the override if the file exists. 2. `@includeWhen($showComparison, 'plans.comparison')` - render the table only when the controller asked for it. 3. `@includeIsolated('plans.card', ['plan' => $plan, 'current' => $currentPlan])` - a card whose inputs are exactly its two parameters. 4. `@each('plans.feature-row', $plan->features, 'feature', 'plans.no-features')` - a feature list with its own empty state. ## When a component is the better tool The Blade docs note that **components** offer similar reuse with data and attribute binding. A component declares its inputs as props and receives an attribute bag, which an include cannot. Includes remain fine for simple fragments - a flash-message block, a shared form section - where passing the parent's context is the point. Components are covered in their own material. ## Pitfalls - `@include` of a view name built from user input can render any template in `resources/views`; keep view names to a known list. - `@includeIf` hides typos: a misspelt view name renders nothing instead of failing loudly. Use it only when absence is legitimate. - Avoid `__DIR__` and `__FILE__` in partials; they point at the compiled file, not the source.

  • Can a partial rendered by @include read the parent loop's $loop variable?
    Yes. `@include` merges `get_defined_vars()` from the compiled parent, and inside a `@foreach` that includes `$loop`. A card partial can therefore check `$loop->first` directly - convenient, but it ties the partial to being included from a loop. Passing an explicit flag keeps it reusable.
  • Why does a partial rendered with @each fail with an undefined variable that worked under @include?
    `@each` renders each item with only the item variable and `$key`, not the parent's locals, so anything the partial read from the parent scope is gone. Globally shared view data is still there. Switch to `@foreach` with `@include`, or pass the needed values into the items themselves.

saying these in an interview costs you the question

  • @include passes only the array you give it
  • @each partials can read the parent view's variables
  • @includeIf is a safe default for every include
  • @includeIsolated also hides data shared with View::share
  • @includeWhen checks whether the view file exists