Livewire v3 Has Been Released

Published on by

Livewire v3 Has Been Released image

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.

Jason Beggs photo

TALL stack (Tailwind CSS, Alpine.js, Laravel, and Livewire) consultant and owner of roasted.dev.

Cube

Laravel Newsletter

Join 40k+ other developers and never miss out on new tips, tutorials, and more.

image
Larafast: Laravel SaaS Starter Kit

Larafast is a Laravel SaaS Starter Kit with ready-to-go features for Payments, Auth, Admin, Blog, SEO, and beautiful themes.

Visit Larafast: Laravel SaaS Starter Kit
Laravel Forge logo

Laravel Forge

Easily create and manage your servers and deploy your Laravel applications in seconds.

Laravel Forge
Tinkerwell logo

Tinkerwell

The must-have code runner for Laravel developers. Tinker with AI, autocompletion and instant feedback on local and production environments.

Tinkerwell
No Compromises logo

No Compromises

Joel and Aaron, the two seasoned devs from the No Compromises podcast, are now available to hire for your Laravel project. ⬧ Flat rate of $7500/mo. ⬧ No lengthy sales process. ⬧ No contracts. ⬧ 100% money back guarantee.

No Compromises
Kirschbaum logo

Kirschbaum

Providing innovation and stability to ensure your web application succeeds.

Kirschbaum
Shift logo

Shift

Running an old Laravel version? Instant, automated Laravel upgrades and code modernization to keep your applications fresh.

Shift
Bacancy logo

Bacancy

Supercharge your project with a seasoned Laravel developer with 4-6 years of experience for just $2500/month. Get 160 hours of dedicated expertise & a risk-free 15-day trial. Schedule a call now!

Bacancy
Lucky Media logo

Lucky Media

Bespoke software solutions built for your business. We ♥ Laravel

Lucky Media
Lunar: Laravel E-Commerce logo

Lunar: Laravel E-Commerce

E-Commerce for Laravel. An open-source package that brings the power of modern headless e-commerce functionality to Laravel.

Lunar: Laravel E-Commerce
LaraJobs logo

LaraJobs

The official Laravel job board

LaraJobs
Larafast: Laravel SaaS Starter Kit logo

Larafast: Laravel SaaS Starter Kit

Larafast is a Laravel SaaS Starter Kit with ready-to-go features for Payments, Auth, Admin, Blog, SEO, and beautiful themes. Available with VILT and TALL stacks.

Larafast: Laravel SaaS Starter Kit
SaaSykit: Laravel SaaS Starter Kit logo

SaaSykit: Laravel SaaS Starter Kit

SaaSykit is a Laravel SaaS Starter Kit that comes with all features required to run a modern SaaS. Payments, Beautiful Checkout, Admin Panel, User dashboard, Auth, Ready Components, Stats, Blog, Docs and more.

SaaSykit: Laravel SaaS Starter Kit
Rector logo

Rector

Your partner for seamless Laravel upgrades, cutting costs, and accelerating innovation for successful companies

Rector

The latest

View all →
New Video Series: The Laravel Ecosystem image

New Video Series: The Laravel Ecosystem

Read article
DirectoryTree Authorization is a Native Role and Permission Management Package for Laravel image

DirectoryTree Authorization is a Native Role and Permission Management Package for Laravel

Read article
Sort Elements with the Alpine.js Sort Plugin image

Sort Elements with the Alpine.js Sort Plugin

Read article
Anonymous Event Broadcasting in Laravel 11.5 image

Anonymous Event Broadcasting in Laravel 11.5

Read article
Microsoft Clarity Integration for Laravel image

Microsoft Clarity Integration for Laravel

Read article
Apply Dynamic Filters to Eloquent Models with the Filterable Package image

Apply Dynamic Filters to Eloquent Models with the Filterable Package

Read article