Getting Started with Laravel Livewire 3: Building Reactive Components
Livewire 3 changes the game for full-stack Laravel devs. In this walkthrough we build a reactive search component from scratch — state, hydration, lazy loading, and the new wire:model.live behaviour — without writing a single line of Vue or React.
Why Livewire Changed Everything for Me
Before Livewire, adding real-time behaviour to a Laravel app meant context-switching to Vue or React. That's fine for SPAs, but for the CRUD-heavy admin panels and government dashboards I build for clients across Indonesia, a full JavaScript framework is overkill.
Livewire 3 is Caleb Porzio's third major iteration. It ships with a fundamentally different hydration strategy — Snapshot Morphing — that fixes the flicker and full-component re-render issues that haunted v2. In this article we'll build a reactive search component from scratch and explore what makes v3 feel genuinely different.
Setting Up a Fresh Livewire 3 Project
Install via Composer, then publish the config once:
composer require livewire/livewire
php artisan livewire:publish --configScript and style injection happens automatically via @livewireStyles and @livewireScripts in your layout. No Vite plugin or manual asset steps required.
Building a Reactive Search Component
Let's build a product search that debounces input and paginates results in real time. First, generate the component:
php artisan make:livewire ProductSearchThen fill in the class:
namespace App\Livewire;
use Livewire\Component;
use Livewire\WithPagination;
use App\Models\Product;
class ProductSearch extends Component
{
use WithPagination;
public string $search = '';
public function updatingSearch(): void
{
$this->resetPage();
}
public function render()
{
return view('livewire.product-search', [
'products' => Product::search($this->search)->paginate(12),
]);
}
}Key v3 difference: Public properties are declared directly on the class with no magic array. The
#[Url]attribute replaces the old$queryStringapproach for URL persistence — cleaner and IDE-friendly.
The wire:model.live Behaviour
The new wire:model.live syncs state on every input event with built-in debounce support, replacing the v2 defer / lazy split:
<input
wire:model.live.debounce.350ms="search"
type="search"
placeholder="Search products…"
class="w-full border rounded-lg px-4 py-2"
/>The .350ms suffix means Livewire waits 350 milliseconds after the last keystroke before dispatching a network request. Tune this to taste — I usually land between 300–500ms for search fields.
Skeleton Loading States
Livewire 3's wire:loading directive makes skeleton UIs trivial to implement:
{{-- Shown while re-rendering --}}
<div wire:loading class="animate-pulse space-y-3">
<div class="h-8 bg-gray-200 rounded"></div>
<div class="h-4 bg-gray-100 rounded w-3/4"></div>
</div>
{{-- Hidden while loading --}}
<div wire:loading.remove>
@foreach ($products as $product)
<x-product-card :product="$product" />
@endforeach
</div>You can scope loading indicators to specific actions using wire:target="search", so a spinner only appears next to the search input rather than blanking the whole page.
Computed Properties: Memoised Per Request
One of my favourite v3 features is the #[Computed] attribute. Use it for anything derived from state — results are cached for the lifetime of the request:
use Livewire\Attributes\Computed;
#[Computed]
public function stats(): array
{
return [
'total' => $this->products->total(),
'showing' => $this->products->count(),
];
}Then in your Blade template: {{ $this->stats['total'] }}. No redundant DB queries.
Things I'd Do Differently
Keep Livewire for state, Blade for structure. Don't nest business logic inside component templates.
Avoid deep component nesting. Morphing handles it, but each extra level adds latency on slow mobile connections.
Profile with Telescope. Livewire requests show up as separate HTTP calls — easy to spot N+1 issues before they hit production.
Conclusion
Livewire 3 delivers on its promise of reactive UIs without leaving PHP. For most Laravel projects I take on — government portals, admin panels, e-learning platforms — it's the right trade-off between developer experience and runtime complexity.
The next time a client asks for "a bit of interactivity," you can reach for Livewire 3 instead of spinning up a full Vue or React build pipeline. Your future self (and your deploy pipeline) will thank you.
More in Tutorial
Optimizing Eloquent Queries: From N+1 to N
A real-world refactor of a slow dashboard page — the queries before, the queries after, and the eager-loading patterns that I now reach for on every project.
Deploying Laravel to Shared Hosting: Complete Guide for cPanel
A pragmatic guide for shipping a Laravel app onto an Indonesian shared host. Covers the public_html dance, queue workers via cron, and the gotchas around mod_rewrite and PHP version pinning.
Implementing Real-time Notifications with Laravel Reverb
Replacing Pusher with the first-party Laravel Reverb server. Setup, channel auth, scaling considerations, and a working chat demo at the end.