What's new in Livewire v4.0

Livewire v4 brings a significant shift in how components are structured and used, introducing a new view-first approach that allows you to define both your PHP logic and Blade markup in a single, streamlined file. It’s a cleaner, more intuitive way to build components that reduces friction and boosts maintainability.
Alongside this, v4 delivers long-requested features like true Blade-style slots, component attributes, performance improvements, and better testing support—without introducing major breaking changes. Whether you're building small widgets or complex UIs, Livewire v4 is designed to help you move faster with less boilerplate.
Let’s dive into what’s new. 👇
View-First Components: One File to Rule Them All ⚡
Livewire v4 introduces a new view-first approach with single-file components.
-
Your Livewire components now live in
resources/views/components/
with a.wire.php
suffix. -
This keeps the PHP logic and Blade markup together in a clean, easy-to-read file.
-
Example:
resources/views/components/counter.wire.php
@php
new class extends Livewire\Component {
public $count = 0;
public function increment() { $this->count++; }
}
@endphp
<div>
Count: {{ $count }}
<button wire:click="increment">Increment</button>
</div>
Prefer the classic class-based setup? You still can do it this way!
Just reference your component class at the top:
@php(new \App\Livewire\Components\Counter)
<div>
Count: {{ $count }}
<button wire:click="increment">Increment</button>
</div>
Slot Support
One of the most requested features is going to make it in Livewire v4: Blade-style slot support in Livewire components.
Default Slots:
<wire:modal>Create Post</wire:modal>
In your modal component:
<div>
{{ $slot }}
</div>
You can also define named Slots:
<wire:modal>
<wire:slot name="header">
<h1>Create post</h1>
</wire:slot>
<form>...</form>
</wire:modal>
And in your component:
@if ($header = $slot('header'))
{{ $header }}
@endif
{{ $slot }}
This brings real flexibility and composability to Livewire UIs, without workarounds.
Component Attributes
You will be able to pass HTML attributes and class names directly to Livewire components, similar to Blade components.
<wire:alert type="error" class="mb-4" id="error-alert">
Something went wrong!
</wire:alert>
And inside the component:
<div {{ $attributes->merge(['class' => 'alert alert-'.$type]) }}>
{{ $slot }}
</div>
More Developer Experience Goodies 😍
• No Breaking Changes (Mostly)
The upgrade path is smooth. Most users should be able to move to v4 without rewriting anything.
• Testing Boost with Pest v4
You’ll be able to run browser-based tests on Livewire components using Pest v4 (launching August 21). Expect slick, real-time testing with component interactions.
• PHP 8.4 Support
Livewire v4 fully supports PHP 8.4 property accessors (getters/setters). For example, you can now prevent a counter from going negative using a setter method.
New File Naming Conventions
-
Use
.livewire.php
to make it clear you’re working with a Livewire component. -
Optional: use the ⚡ emoji if you’re feeling spicy:
⚡counter.blade.php
• Multi-File Components
Want a more structured setup? Use:
php artisan make:livewire counter --mfc
This will generate the following files:
- counter/counter.php
- counter/counter.blade.php
- counter/counter.js
- counter/counter.test.php
New Performance & UI Tricks 🚀
• @island
Directive
Segment expensive parts of your Livewire views. It’s like partial hydration—slow parts won’t block the rest of the page from rendering.
• Blaze Pre-Compiler
Blade components will be code-folded and precompiled with Blaze, reducing render times massively!
In the demo done by Caleb in Laracon US 2025, rendering time went from 329ms down to 19ms!
• Effortless Loading States
Triggering a Livewire request now automatically adds data-loading
to the HTML element. You can use data-loading:
as a class prefix to show spinners or change styles—no JavaScript required.
<button wire:click="save" class="btn" data-loading:class="opacity-50">
Save
</button>
• Targeted Event Dispatching
Send events to specific components using wire:ref
:
<?php
new class extends Livewire\Component {
public $name = '';
public function save()
{
$this->validate(['name' => 'required']);
// ...
$this->dispatch('close')->to(ref: 'modal');
}
};
?>
<div>
<livewire:modal wire:ref="modal">
<form wire:submit="save" class="space-y-6">
<!-- ... -->
</form>
</livewire:modal>
</div>
This code snippet demonstrates targeted event dispatching in Livewire v4 using the new wire:ref
and dispatch()->to()
API.
In this example:
-
A modal component is given a reference using
wire:ref="modal"
. -
A parent Livewire component (defined anonymously here) includes a
save()
method that validates the input (name
field). -
After validation, the component dispatches a
close
event specifically to the child modal component by calling:
$this->dispatch('close')->to(ref: 'modal');
Conclusion
Livewire v4 trims the fat, sharpens the edges, and gives you more control with less ceremony. Whether you prefer the new single-file components or stick with the classic structure, the additions feel like natural extensions, not distractions. It’s a release that respects your workflow and quietly upgrades your toolkit.
As for the ⚡ in the filename, I have mixed feelings. It’s clever and a bit playful, but feels more like an inside joke than something I’d use in production.
Either way, I can’t wait to get hands-on with Livewire v4.0.
Until then, keep building great things.