Blade Fragments
Send only the parts of your views that changed.
Overview
Blade Fragments let you define named sections within your views that can be rendered independently. Instead of sending an entire view, you send just the fragment that changed.
This is more efficient than full view rendering and keeps your templates DRY—the same view works for both full page loads and partial updates.
Defining Fragments
Use the @fragment directive to mark sections of your Blade views:
<!-- resources/views/posts/index.blade.php -->
<div class="posts-page">
<h1>Posts</h1>
@fragment('posts-list')
<div id="posts-list">
@foreach($posts as $post)
<article class="post">
<h2>{{ $post->title }}</h2>
<p>{{ $post->excerpt }}</p>
</article>
@endforeach
</div>
@endfragment
@fragment('pagination')
<nav id="pagination">
{{ $posts->links() }}
</nav>
@endfragment
</div>
<!-- resources/views/posts/index.blade.php -->
<div class="posts-page">
<h1>Posts</h1>
@fragment('posts-list')
<div id="posts-list">
@foreach($posts as $post)
<article class="post">
<h2>{{ $post->title }}</h2>
<p>{{ $post->excerpt }}</p>
</article>
@endforeach
</div>
@endfragment
@fragment('pagination')
<nav id="pagination">
{{ $posts->links() }}
</nav>
@endfragment
</div>
Fragment Naming
Rendering Fragments
Single Fragment
Use fragment() to render and patch a single fragment:
return gale()
->fragment('posts.index', 'posts-list', [
'posts' => Post::paginate(10),
]);
return gale()
->fragment('posts.index', 'posts-list', [
'posts' => Post::paginate(10),
]);
The three arguments are:
- View name — The Blade view containing the fragment
- Fragment name — The name used in
@fragment('name') - Data — Variables to pass to the view
With Options
Pass options to control where and how the fragment is patched:
return gale()
->fragment('posts.index', 'posts-list', $data, [
'selector' => '#posts-list', // Target element
'mode' => 'morph', // Update mode
]);
return gale()
->fragment('posts.index', 'posts-list', $data, [
'selector' => '#posts-list', // Target element
'mode' => 'morph', // Update mode
]);
Multiple Fragments
Use fragments() to send multiple fragments in a single response:
return gale()
->fragments([
[
'view' => 'posts.index',
'fragment' => 'posts-list',
'data' => compact('posts'),
'options' => ['selector' => '#posts-list'],
],
[
'view' => 'posts.index',
'fragment' => 'pagination',
'data' => compact('posts'),
'options' => ['selector' => '#pagination'],
],
]);
return gale()
->fragments([
[
'view' => 'posts.index',
'fragment' => 'posts-list',
'data' => compact('posts'),
'options' => ['selector' => '#posts-list'],
],
[
'view' => 'posts.index',
'fragment' => 'pagination',
'data' => compact('posts'),
'options' => ['selector' => '#pagination'],
],
]);
Each fragment is sent as its own SSE event, allowing the browser to update multiple sections efficiently.
View Macro
Gale adds a renderFragment macro to Laravel's View facade for getting fragment HTML directly:
use Illuminate\Support\Facades\View;
$html = View::renderFragment('posts.index', 'posts-list', [
'posts' => $posts,
]);
// Returns the rendered HTML string
use Illuminate\Support\Facades\View;
$html = View::renderFragment('posts.index', 'posts-list', [
'posts' => $posts,
]);
// Returns the rendered HTML string
This is useful when you need the fragment HTML for other purposes, like caching or testing.
Nested Fragments
Fragments can be nested inside each other:
@fragment('sidebar')
<aside id="sidebar">
<h3>Categories</h3>
@fragment('category-list')
<ul id="category-list">
@foreach($categories as $category)
<li>{{ $category->name }}</li>
@endforeach
</ul>
@endfragment
</aside>
@endfragment
@fragment('sidebar')
<aside id="sidebar">
<h3>Categories</h3>
@fragment('category-list')
<ul id="category-list">
@foreach($categories as $category)
<li>{{ $category->name }}</li>
@endforeach
</ul>
@endfragment
</aside>
@endfragment
You can render either fragment independently:
// Render just the category list
return gale()->fragment('layout', 'category-list', compact('categories'));
// Or render the entire sidebar including the list
return gale()->fragment('layout', 'sidebar', compact('categories'));
// Render just the category list
return gale()->fragment('layout', 'category-list', compact('categories'));
// Or render the entire sidebar including the list
return gale()->fragment('layout', 'sidebar', compact('categories'));
Practical Example
Here's a complete example of a search page with fragments:
The View
<!-- resources/views/products/search.blade.php -->
<div class="search-page"
x-data="{ query: '' }">
<input type="text"
x-model="query"
@input.debounce.300ms="$postx('/products/search')"
placeholder="Search products...">
@fragment('results')
<div id="results" x-loading.class="opacity-50">
@forelse($products as $product)
<div class="product">
<h3>{{ $product->name }}</h3>
<p>{{ $product->price }}</p>
</div>
@empty
<p>No products found.</p>
@endforelse
</div>
@endfragment
@fragment('count')
<p id="count">
Showing {{ $products->count() }} of {{ $products->total() }} products
</p>
@endfragment
</div>
<!-- resources/views/products/search.blade.php -->
<div class="search-page"
x-data="{ query: '' }">
<input type="text"
x-model="query"
@input.debounce.300ms="$postx('/products/search')"
placeholder="Search products...">
@fragment('results')
<div id="results" x-loading.class="opacity-50">
@forelse($products as $product)
<div class="product">
<h3>{{ $product->name }}</h3>
<p>{{ $product->price }}</p>
</div>
@empty
<p>No products found.</p>
@endforelse
</div>
@endfragment
@fragment('count')
<p id="count">
Showing {{ $products->count() }} of {{ $products->total() }} products
</p>
@endfragment
</div>
The Controller
public function search()
{
$query = request()->state('query', '');
$products = Product::search($query)->paginate(20);
return gale()
->fragment('products.search', 'results', compact('products'), [
'selector' => '#results',
])
->fragment('products.search', 'count', compact('products'), [
'selector' => '#count',
]);
}
public function search()
{
$query = request()->state('query', '');
$products = Product::search($query)->paginate(20);
return gale()
->fragment('products.search', 'results', compact('products'), [
'selector' => '#results',
])
->fragment('products.search', 'count', compact('products'), [
selector' => '#count',
]);
}
Why Use Fragments?
DRY Templates
One view file serves both full pages and partial updates.
Efficient
Send only what changed, not the entire page.
Maintainable
Logic stays together—no duplicate partials.
Progressive
Works without JavaScript—full page loads still work.
Quick Reference
| Method/Directive | Description |
|---|---|
@fragment('name') |
Start a named fragment section |
@endfragment |
End the fragment section |
gale()->fragment($view, $name, $data) |
Render and send a fragment |
gale()->fragments([...]) |
Send multiple fragments |
View::renderFragment($view, $name, $data) |
Render fragment to HTML string |