Laravel Blade Foreach Loop: Complete Guide with the $loop Variable and @forelse

Avatar
M

Maksudur Rahman

Software Engineer••
7843Views
5mRead
0Reactions

Iterating through collections and arrays in Laravel Blade templates is more powerful than native PHP foreach. Blade provides syntactic shortcuts, empty collection fallbacks, and the automatic $loop variable.

Here is the complete guide to mastering loops in Blade.


1. Basic @foreach Syntax

The standard Blade loop:

<ul>
    @foreach ($users as $user)
        <li>{{ $user->name }} ({{ $user->email }})</li>
    @endforeach
</ul>

2. Handling Empty Collections with @forelse

Avoid wrapping @foreach inside an @if(count($items)) check. Blade provides @forelse to display an empty state cleanly:

<div class="user-list">
    @forelse ($users as $user)
        <div class="user-card">
            <h3>{{ $user->name }}</h3>
            <p>{{ $user->role }}</p>
        </div>
    @empty
        <div class="empty-state">
            <p>No active users found.</p>
        </div>
    @endforelse
</div>

3. The Magic $loop Variable

Inside every @foreach and @forelse block, Laravel automatically injects a $loop object. You do not need to initialize a manual $i = 0 counter:

Property

Description

Example Use Case

$loop->index

Zero-based index (0, 1, 2...)

CSS grid calculation

$loop->iteration

1-based index (1, 2, 3...)

Numbered lists, table rows

$loop->remaining

Number of items remaining

Countdown displays

$loop->count

Total number of items

"Item 3 of 10"

$loop->first

Boolean, true on first iteration

Highlight top result / banner

$loop->last

Boolean, true on final iteration

Skip divider line on last item

$loop->even

Boolean, true on even iterations

Zebra striping table rows

$loop->odd

Boolean, true on odd iterations

Alternating styling

$loop->depth

Integer depth level of nested loop

Multi-level tree indentation

$loop->parent

Access parent $loop in nested loops

Combined counters in child tables

Practical Example: Table Zebra Striping and Badges

<table>
    <thead>
        <tr>
            <th>#</th>
            <th>Name</th>
            <th>Status</th>
        </tr>
    </thead>
    <tbody>
        @forelse ($orders as $order)
            <tr class="{{ $loop->even ? 'bg-gray-50' : 'bg-white' }}">
                <td>{{ $loop->iteration }}</td>
                <td>{{ $order->customer_name }}</td>
                <td>
                    @if($loop->first)
                        <span class="badge badge-primary">Latest Order</span>
                    @endif
                    {{ $order->status }}
                </td>
            </tr>
        @empty
            <tr>
                <td colspan="3">No orders found.</td>
            </tr>
        @endforelse
    </tbody>
</table>

4. Nested Loops and $loop->parent

When looping through categories and their products, use $loop->parent to check the outer iteration:

@foreach ($categories as $category)
    <h2>{{ $loop->iteration }}. {{ $category->name }}</h2>

    <ul>
        @foreach ($category->products as $product)
            <li>
                Category {{ $loop->parent->iteration }}, Product {{ $loop->iteration }}:
                {{ $product->name }}
            </li>
        @endforeach
    </ul>
@endforeach

5. Performance: Avoid N+1 Queries in Blade Loops

The most common bug in Blade loops is querying relations inside the iteration:

{{-- BAD: Triggers a query for every single post (N+1 Problem) --}}
@foreach ($posts as $post)
    <p>{{ $post->author->name }}</p>
@endforeach

Always eager load relationships in your controller before passing data to Blade:

// In Controller:
$posts = Post::with('author')->get();
return view('posts.index', compact('posts'));

Recommended Resources & Courses

Partner Links

React to this article