In Blade, how do @include, @includeIf, @includeWhen, @includeFirst, @includeIsolated and @each differ, especially in which variables the included view can see?
answer
- @include passes get_defined_vars()
- missing view: @include throws, @includeIf skips
- When/Unless take a boolean first
- @includeIsolated: only what you pass
- @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@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
Recall that @include inherits the parent's variables and throws on a missing view, while @includeIf and @includeWhen add conditions.
Explain the get_defined_vars() merge behind @include, what @includeIsolated and @each pass instead, and that shared view data reaches all of them.
Choose isolation deliberately to keep partials decoupled, avoid @includeIf hiding typos, and know when a component with props replaces an include.
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