Reader Stacks

Laravel Blade Fundamentals: Variables, Conditionals, Loops, and Raw HTML

{!! !!} deliberately skips Blade's automatic HTML escaping — the right choice for trusted, pre-sanitized HTML, and an XSS vulnerability waiting to happen for anything containing raw user input.

Laravel Blade Fundamentals: Variables, Conditionals, Loops, and Raw HTML

Four Blade fundamentals — declaring a template-local variable, conditionals, loops, and rendering raw (unescaped) HTML — cover the large majority of what a typical Blade view actually needs beyond simple variable interpolation.

Declaring a variable directly in a Blade template

@php
    $discountedPrice = $product->price * 0.9;
@endphp

Discounted price: {{ $discountedPrice }}

@php/@endphp allows writing arbitrary PHP directly in a template — genuinely useful for a quick, view-local calculation, though logic that's more involved than a one-line computation is generally better placed in the controller or a view composer instead, keeping the template itself focused on presentation.

The shorter @php single-line syntax

@php($discountedPrice = $product->price * 0.9)

Conditionals: @if, @elseif, @else

@if ($product->stock === 0)
    Out of stock
@elseif ($product->stock < 5)
    Low stock
@else
    In stock
@endif

Blade's convenience conditionals

@unless ($user->isSubscribed())
    Subscribe now
@endunless

@isset($product->discount)
    

Discount: {{ $product->discount }}%

@endisset @empty($cart->items)

Your cart is empty.

@endempty

@unless is simply the inverse of @if — genuinely just a readability preference for a condition more naturally expressed as a negative; @isset and @empty map directly to PHP's own isset() and empty() functions.

Loops: @foreach and its loop variable

@foreach ($products as $product)
    
{{ $loop->iteration }}. {{ $product->name }} @if ($loop->first) (first item) @endif @if ($loop->last) (last item) @endif
@endforeach

Blade's special $loop variable, automatically available inside any @foreach, provides iteration (1-based index), index (0-based), first, last, and count — all without needing to manually track a counter variable the way plain PHP would require.

@forelse: a loop with a built-in empty-state check

@forelse ($products as $product)
    
{{ $product->name }}
@empty

No products found.

@endforelse

@forelse combines a loop and an empty-collection check into one construct — functionally equivalent to a plain @foreach wrapped in an if ($products->isEmpty())/else check, just more concise for this specific, very common pattern.

Nested loop access via $loop->parent

@foreach ($categories as $category)
    @foreach ($category->products as $product)
        

{{ $loop->parent->iteration }}.{{ $loop->iteration }} {{ $product->name }}

@endforeach @endforeach

Rendering raw, unescaped HTML

{{ $post->body }}   {{-- HTML tags shown as literal escaped text --}}
{!! $post->body !!} {{-- HTML tags rendered as actual markup --}}

Blade's standard {{ }} automatically escapes output through htmlspecialchars(), preventing XSS by treating any HTML in the value as literal text — {!! !!} deliberately skips this escaping, and should only ever be used for genuinely trusted, pre-sanitized HTML (like rich-text content from a trusted CMS field), never for raw, unsanitized user input, which would otherwise create a direct XSS vulnerability.

Comments in Blade (never rendered, even in the HTML source)

{{-- This comment is completely stripped, unlike an HTML comment --}}

Unlike a standard HTML comment (, which is still sent to and visible in the browser's page source), a Blade comment is fully stripped during compilation — never present in the final rendered output at all, useful for notes meant only for developers reading the template source.