Building the Future with Livewire 4: Unified Components, Blaze, and Islands Architecture
Overview
Prerequisites
To follow along with these techniques, you should have a solid grasp of:
- PHP & Laravel basics: Understanding of routing, Blade templates, and class structures.
- Livewire 3: Familiarity with how state and actions work in the current version.
- Alpine.js: Basic knowledge of client-side reactivity.
- Tailwind CSS: Useful for implementing the new loading indicator patterns.
Key Libraries & Tools
- Livewire 4: The core full-stack framework for Laravel.
- Blaze: A new optimization layer that "code-folds" Blade components to remove runtime overhead.
- Pest 4: A testing framework used for high-level browser testing within components.
- Flux UI: A high-quality component kit that benefits from these performance upgrades.
- Sushi: An array-to-Eloquent driver mentioned as a community favorite.
Code Walkthrough: The Unified Component Model
In resources/views/components alongside your standard Blade components.
Single-File Components
Creating a counter now looks like this:
<?php
use function Livewire\{state, rules};
new class extends Livewire\Component {
public $count = 0;
public function increment() {
$this->count++;
}
};
?>
<div>
<button wire:click="increment">+</button>
<span>{{ $count }}</span>
</div>
<script>
this.watch('count', (value) => {
console.log('Count changed to: ' + value);
});
</script>
In this example, the logic, view, and script live together. Notice the <script> tag at the bottom—it no longer requires @script directives. The this keyword in $wire syntax, offering a more native feel. These scripts are served as ES6 modules, meaning they are cached by the browser and can use native imports.
Multi-File Conversion
If a component grows too large, you can automatically convert it to a Multi-File Component (MFC) using the CLI. This moves the logic into a dedicated directory with separate .php, .blade.php, and .js files, maintaining
Syntax Notes: PHP 8.4 Property Hooks
updating and updated lifecycle methods.
Validation with Setters
You can now intercept property updates directly at the language level:
public int $count = 0 {
set => max(0, $value);
}
Memoization with Getters
Instead of creating custom computed property methods, use native getters. These are excellent for deriving state for your views:
public int $multiple {
get => $this->count * 5;
}
You can even use asymmetric visibility (public get, protected set) to make a property readable by the view but immutable from the client, effectively replacing the @locked attribute.
The Blaze Compiler: Vaporizing Runtime Overhead
One of the most impressive technical feats in version 4 is Blaze.
Blaze uses a technique called code folding. It parses your Blade templates and identifies static parts—like
Practical Examples: Islands and Infinite Scroll
Islands architecture allows you to isolate expensive parts of a page so they don't block the rest of the UI. This is a game-changer for dashboards with slow database queries.
Implementing an Island
Wrap a slow section in the @island directive:
@island('revenue-chart', lazy: true)
<div class="chart">
{{ $this->expensiveRevenueQuery() }}
</div>
@placeholder
<x-skeleton-loader />
@endisland
By setting lazy: true, the main page loads instantly.
Infinite Pagination
Islands also unlock high-performance pagination. By changing the render mode to append, you can create an infinite scroll effect with minimal code:
@island('reports', mode: 'append')
@foreach($reports as $report)
<div>{{ $report->title }}</div>
@endforeach
@endisland
<button wire:intersect="$paginator->nextPage()" wire:island="reports">
Loading more...
</button>
The wire:intersect directive triggers the next page when the button enters the viewport, and because the island is in append mode, it only fetches and patches the new results into the DOM.
Tips & Gotchas
- Priority Polling: In Livewire 4, human-initiated actions (like clicks) now automatically cancel background polling requests. This prevents the UI from feeling "locked" when background updates are happening.
- Data Loading Attributes: Any element triggering a request now receives a
data-loadingattribute. UseTailwind CSSmodifiers likedata-loading:opacity-50to handle loading states without writing complexwire:loadinglogic. - Ref Management: Use
wire:ref="myModal"to target specific components for events. This solves the issue of global event listeners accidentally closing every modal on the page when only one was intended. - PHP 8.4 Requirement: To use the advanced property hooks, you must ensure your server is running PHP 8.4. WhileLivewire 4aims for "mostly no breaking changes," these specific syntax upgrades require modern PHP.
