@if
Renders a block of a template only when a PHP expression evaluates to true.
@if ($condition) ... @elseif ($condition) ... @else ... @endifParameters
| Parameter | Type | Description |
|---|---|---|
$condition | mixed | Any PHP expression. It is copied verbatim into the compiled view and evaluated with PHP's normal truthiness rules. |
Return value
Nothing — the directive emits the first branch whose condition is truthy into the rendered output.
Errors
A malformed expression or a missing @endif produces invalid PHP, which surfaces as a ParseError pointing at the compiled file under storage/framework/views.
@if, @elseif, @else and @endif compile straight to PHP's if, elseif, else and endif. There is no expression language of its own: whatever you write between the parentheses is pasted into the compiled view, so method calls, comparisons and null coalescing all behave exactly as they do in PHP.
When to reach for it
Use it for presentation branches — an empty state, a badge that only appears for overdue invoices, a nav item shown to owners. When the condition encodes a business rule, move it into a model method, a policy or a view model and call that from the template; the view stays readable and the rule becomes testable.
The narrower directives
Blade ships shortcuts for the common checks: @isset (defined and not null), @empty, @unless, @auth and @guest (both accept a guard name), @production, @env, @hasSection and @sectionMissing. Prefer them over hand-rolled equivalents — @isset($x) will not warn on an undefined variable the way @if ($x) does.
What trips people up
Indentation is preserved in the output, so conditional whitespace inside <pre> or an email template can shift. And a stray @endforeach where @endif belongs fails at compile time with a line number from the cached file, not from your template.
Example
<?php
use Illuminate\Support\Facades\Blade;
$template = <<<'BLADE'
@if ($records->count() === 1)
I have one record!
@elseif ($records->count() > 1)
I have {{ $records->count() }} records!
@else
I don't have any records!
@endif
BLADE;
echo Blade::render($template, ['records' => collect(['a', 'b'])]);
// I have 2 records!When to use it
- Show an 'overdue' badge only when an invoice's due date has passed
- Render an admin-only action link inside a shared table row partial
- Fall back to placeholder markup when an optional relation was not eager loaded
Frequently asked questions
How do I write an else if in a Blade template?
Use @elseif ($condition) between @if and @endif — the directive maps directly onto PHP's elseif. Blade has no @elsif or @else if spelling, and using one silently emits the text as HTML.
Can I call a method or a helper inside a Blade @if?
Yes — anything between the parentheses is copied verbatim into the compiled PHP, so method calls, helper functions and comparisons all work. Keep complex rules in a model method or view model so the template stays readable.
Why does my Blade condition report an error in a file I never wrote?
Blade compiles each template into storage/framework/views, and PHP reports syntax errors against that cached file. Run php artisan view:clear to drop stale copies, then match the reported line back to your .blade.php source.
More examples
What it compiles to
The compiled file shows why the directive has no special semantics of its own — it is a one-to-one translation into PHP's alternative if syntax. Reading the cached file is the fastest way to debug a condition that behaves unexpectedly, because it shows exactly which expression Blade extracted from the parentheses.
<?php
// resources/views/orders/show.blade.php
$source = <<<'BLADE'
@if ($order->isPaid())
Paid
@else
Awaiting payment
@endif
BLADE;
// storage/framework/views/<hash>.php
$compiled = <<<'PHP'
<?php if ($order->isPaid()): ?>
Paid
<?php else: ?>
Awaiting payment
<?php endif; ?>
PHP;
echo $compiled;The narrower conditional directives
@isset is skipped because the variable is defined but @empty matches the empty array. @auth needs a booted authentication guard and @production reads the application environment, so both are inert outside a full application. Reaching for these instead of @if (isset($x) && ! empty($x)) keeps the intent visible and avoids undefined-variable warnings.
<?php
use Illuminate\Support\Facades\Blade;
$template = <<<'BLADE'
@isset($records)
$records is defined and is not null...
@endisset
@empty($records)
$records is "empty"...
@endempty
@auth('admin')
Shown to users on the admin guard...
@endauth
@production
Analytics snippet...
@endproduction
BLADE;
echo Blade::render($template, ['records' => []]);
// $records is "empty"...Moving the rule out of the view
The view asks one question instead of restating the rule as `$invoice->due_at < now() && ! $invoice->paid_at`. The condition can now be unit tested, and every template that needs the same badge stays in sync when the definition of overdue changes.
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Invoice extends Model
{
public function isOverdue(): bool
{
return $this->due_at->isPast() && $this->paid_at === null;
}
}
// resources/views/invoices/row.blade.php
$view = <<<'BLADE'
@if ($invoice->isOverdue())
<span class="badge">Overdue</span>
@endif
BLADE;
echo $view;
Discussion