Livewire v3 Has Been Released
Published on by Jason Beggs
Caleb Porzio just released the official Livewire v3! In his talk at Laracon, he demoed a ton of the new features, some of which we'll cover here, and you can watch the full video:
Rewritten core
The core of Livewire has been totally rewritten from scratch. Rewriting the core was a huge undertaking, but it was necessary to accomplish everything that's included in this release. The new core architecture will also be much easier to maintain for Caleb and the Livewire core contributors.
Alpine utilization
The v3 core now utilizes Alpine to its full potential. Instead of including code for applying DOM updates, adding event listeners, etc., in both Livewire and Alpine, Livewire v3 utilizes Alpine for the heavy lifting. By registering Alpine plugins, Livewire now allows Alpine to do the heavy lifting while still providing the syntactic sugar you've come to love.
This also means Alpine is now included by default with Livewire, so there's no need to load Alpine via a CDN or NPM. It's automatically injected.
In addition, v3 utilizes the Alpine Morph plugin for diffing the DOM and applying updates instead of morphdom. This will lead to fewer DOM-diffing issues and overall better compatibility between Livewire and Alpine.
Improved component nesting
In the past, I considered nesting Livewire components an anti-pattern or something to avoid when possible because of potential performance implications. In v3, that won't be the case!
With reactive props, bundled requests, the new $parent
property, and other improvements, v3 is improving component nesting quite a bit. We'll cover some of these improvements in more detail later in this post.
Improved property serialization
v2 tried to intelligently determine what type properties were on the initial render to rehydrate them as the same types on subsequent requests. v2 didn't support deeply nested hydration though. If you had a collection with mixed types, v2 wouldn't cast each collection item back to its original type. v3 is much smarter about this and stores the type of each item so it can cast them back to proper types on subsequent requests.
Bundled requests
In v2, when multiple components on a page were polling or listening for the same event, Livewire would send separate requests for each component every time it needed to talk to the server. v3 is much more efficient and bundles all those updates into one request.
Better defaults
Blade marker injection
DOM diffing is one of the most common issues you could run into with v2. The issue was typically caused by @if
and similar Blade directives inserting or removing DOM elements. v3 attempts to circumvent those issues by injecting HTML comments (markers) where those Blade directives start and end. By looking for those markers, Livewire can match up new or removed DOM elements with a marker to place them correctly in the DOM.
<form wire:submit="save"> {{-- ... --}} <!-- __BLOCK__ --> @if ($success) <div>Saved!</div> @endif <!-- ENDBLOCK --> <div> <button>Save</button> </div><div>
wire:model
is deferred by default
Originally, Livewire being "live" was a really cool feature, so it was made the default. Upon further thought and observing real-world usage, Caleb realized deferring wire:model
requests was the better default. Most apps don't actually need input values to be synced with the server on every keystroke, so v3 flips the default behavior. The previous wire:model.defer
functionality is the new default when using wire:model
. wire:model.live
has been added to replace the old default behavior on inputs that actually need to be "live".
{{-- Now deferred by default --}}<input wire:model="name"> {{-- Syncs with the server on every keystroke --}}<input wire:model.live="name">
New features
Automatically injected assets
In v3, Livewire automatically injects its styles, scripts, and Alpine. There's no need to add <livewire:styles />
and <livewire:scripts />
or load Alpine in your projects anymore!
New default namespace
By default, v3 uses the App\Livewire
namespace (and app/Livewire
directory) instead of App\Http\Livewire
now. There's a configuration option to keep the old namespace if you prefer that.
Reactive properties
Coming from frontend frameworks like React and Vue, some Livewire users automatically assumed properties they passed into nested components would be reactive to changes in the parent. Due to some limitations in v2, that wasn't actually possible. We had to rely on events or other workarounds to sync nested components. v3 adds support for "reactive" props. It's as simple as adding a #[Reactive]
PHP attribute to the property in your component class.
<?php // ...use Livewire\Attributes\Reactive; class InvoiceItem extends Component{ #[Reactive] public $item;}
Form objects
Form objects are a new concept that can help keep component classes clean by abstracting away some of the form-specific code. You may want to put a component's form properties, validation, saving functionality, and more on form objects.
Here's a small example, but I'd recommend reading the documentation for a full list of the features!
<?php namespace App\Livewire\Forms; use Livewire\Form; class UserForm extends Form{ #[Rule('required')] public $name = ''; #[Rule(['required', 'email'])] public $email = '';}
<?php namespace App\Livewire; use Livewire\Component;use App\Models\Post;use App\Livewire\Forms\UserForm; class UpdateProfile extends Component{ public UserForm $form; public function save() { auth()->user()->update( $this->form->all() ); return $this->redirect('/profile'); } public function render() { return view('livewire.update-profile'); }}
<form wire:submit="save"> <input type="text" wire:model="form.name"> <div> @error('form.name') <span class="error">{{ $message }}</span> @enderror </div> <input type="email" wire:model="form.email"> <div> @error('form.email') <span class="error">{{ $message }}</span> @enderror </div> <button type="submit">Save</button></form>
wire:navigate
(SPA mode)
Another new addition is wire:navigate
. When using full-page Livewire components, you may now add the wire:navigate
attribute to your links to enable a SPA-like experience. Instead of doing a full-page load, Livewire will add a loading indicator to the top of the page, fetch the contents of the new page in the background, then intelligently swap out the HTML on the page. The feature also supports prefetching and redirects and enables the ability for persisted elements.
<a href="/profile" wire:navigate>Profile</a>
@persist
With the addition of wire:navigate
, you may now have "persisted" elements that aren't reloaded when navigating through different pages. This feature will be handy for use cases like audio players that you want to continue playing audio while your users click through different pages.
To use the feature, wrap the element you want to be persisted in the @persist
directive:
@persist('player') <audio src="{{ $episode->file }}" controls></audio>@endpersist
Lazy-loaded components
Livewire now supports lazy-loaded components. Sometimes, you have a component that might slow down initial page loads or is initially hidden inside a modal that you want to lazily load to keep the initial page load fast.
To lazy-load a component add a lazy
attribute to the component in your Blade.
<livewire:your-component lazy />
Livewire will skip rendering that component on the initial page load. Once all the other contents are loaded, a network request will be sent to fully render the component and the component will be inserted into the DOM.
$parent
property
To communicate with "parent" components in previous versions of Livewire, you had to use events and listeners. In v3, there's a new $parent
property you may use to call methods on parent components directly from children.
<div> <span>{{ $item->name }}</span> <button wire:click="$parent.remove({{ $item->id }})">Remove</button></div>
Hybrid methods/evaluating JS from the backend
v3 allows you to write JavaScript methods in your backend components now. By adding the #[Js]
attribute to a method on a component, you may write JavaScript code as a string and Livewire will expose that method to your frontend. When called via wire:click
, the JavaScript will be executed on the frontend with no network requests being sent back to the server.
<?php // ...use Livewire\Attributes\Js; class UsersTable extends Component{ public $filters = []; #[Js] public function reset() { return <<<'JS' $wire.filters = []; JS; } // ...}
<div> <div> <input wire:model.live="filters.active" type="checkbox"> <label>Only active</label> </div> <button wire:click="reset">Reset Filters</button> @foreach ($users as $user) {{-- ... --}} @endforeach</div>
Sometimes, it's useful to execute small bits of JavaScript from your backend methods. v3 enables that via the $this->js()
method. Just call the method and pass in a string of JavaScript and Livewire will execute it on the frontend on the next render.
public function save(){ // ... $this->js("alert('You just executed JS from the backend!')");}
PHP Attribute usage
PHP Attributes are a relatively new and powerful feature to PHP, and Livewire v3 utilizes them heavily for new and existing features.
#[Url]
The new #[Url]
attribute replaces the $query
property from v2. Add #[Url]
above any property on your component and it'll be tracked in the query string.
<?php // ...use Livewire\Attributes\Url; class UsersTable extends Component{ #[Url] public $filters = []; // ...}
#[On]
The new #[On]
attribute replaces the $listeners
property from v2. Add #[On('some-event')]
above a method on your component, and it will be executed whenever that event is dispatched.
<?php // ...use Livewire\Attributes\Url; class UsersTable extends Component{ // ... #[On('filters-reset')] public function resetFilters() { // ... }}
#[Layout]
and #[Title]
The new #[Layout]
and #[Title]
attributes allow you to set the layout view and title for full-page components. They may be added on the render
method of the component or on the class itself.
#[Layout('layouts.app')]public function render(){ return view('livewire.create-post');}
#[Computed]
Replacing v2's getSomeProperty
syntax for computed properties, we have the #[Computed]
attribute. It functions the same as the old syntax but has some new, really powerful additions.
In v2, computed properties could only be cached during a single request. In v3, you can cache a property across multiple requests and even across components. This will make caching expensive database queries a breeze!
use Livewire\Attributes\Computed; // Cache across requests#[Computed(persist: true)]public function user(){ return User::findOrFail($this->userId);} // Cache across all instances of this component#[Computed(cache: true)]public function user(){ return User::findOrFail($this->userId);}
#[Rule]
The new #[Rule]
attribute replaces the $rules
property and rules
method from v2. Add #[Rule(['required', 'max:150'])]
to a property on your component to tell Livewire how the property should be validated.
<?php // ...use Livewire\Attributes\Rule; class InvoiceItem extends Component{ #[Rule(['required', 'max:120'])] public $itemName; // ...}
#[Locked]
The new #[Locked]
attribute allows you to prevent a user from updating a property from the frontend. You may use this as a security measure on properties that users shouldn't be able to change.
<?php // ...use Livewire\Attributes\Locked; class InvoiceItem extends Component{ #[Locked] public $id; // ...}
Upgrading
The upgrade process for most apps will be pretty fast. There's a livewire:upgrade
artisan command that's included in the beta to help with some of the more tedious changes, then you can follow the upgrade guide to ensure everything is up to date.
If you would rather leave the upgrade to Livewire experts, Caleb and I are offering a service to get you a jumpstart on the upgrade process. You can check that out here.
New website design and domain
In addition to all the new features and improvements, the Livewire docs site has been completely redesigned, rebuilt, and rewritten!
The new docs are much more thorough than the v2 docs. They cover each feature in detail and go into depth on how Livewire handles hydration, morphing, and nested components under the hood. I recommend reading through the entire site as you have time. It's a masterclass in building Livewire v3 apps!
Another big announcement is that the docs site is being moved to livewire.laravel.com. Go on over there and check it out!
This was a long post, but there were so many new features to cover! I hope you'll try v3 out soon, and feel free to reach out with feedback on the improvements.
TALL stack (Tailwind CSS, Alpine.js, Laravel, and Livewire) consultant and owner of designtotailwind.com.