Livewire is getting lots of quality-of-life improvements in the latest release (v2.6). This is the biggest Livewire release since version 2.0.
This release is extra special because the majority of these updates were completely PR’d and driven by the community. Special shout out to @joshhanley for developing basically half of them and helping out with most of them.
Here’s the full release notes with links to every feature, fix, and PR that was made for this release: https://github.com/livewire/livewire/releases/tag/v2.6.0
Let’s jump in. Here’s what’s up:
New boot lifecycle hook
As of 2.6, there is a new
boot() lifecycle method available for your Livewire components. This method will run before any other lifecycle hook AND will run on every single request, both initial and subsequent component requests.
If the words “initial and subsequent requests” in the context of Livewire are fuzzy for you, give this post a quick read.
You can also use this lifecycle hook within traits by adding the class name as a suffix to avoid inheritance collisions. For example:
mount() currently runs only on the initial request, and
hydrate() only runs on subsequent ones, there hasn’t been a good way to run code on EVERY request. Many users achieved this by overriding the constructor which is highly discouraged. Now we have
Deep model data binding
Livewire has supported binding directly to Eloquent model attributes for a long time, however, v2.6 takes it to a whole new level.
Let’s look at an example:
If you had an Eloquent model set to a Livewire property like
public $post, you could bind a text input to one of its attributes like so:
However, this mechanism wouldn’t work for binding to attributes of a nested model relationship. After this update, given an Eloquent model property on a Livewire component like
$user, you can now bind directly to deeply nested relationships like so:
Here’s a more fleshed out example of a page for a user to edit all the titles of their posts:
With this setup, you can directly bind the value of an input element to the title of a post on the
This saves on loads of boilerplate code and allows for cleaner Livewire model patterns to emerge in the future.
There is a new
Wireable interface that if present, allows any object to be stored and persisted as a public property on a Livewire component.
Here’s the trait:
This is extremely helpful for using things like custom DTOs (Data Transfer Object) with your Livewire components.
For example, let’s say we have a custom object in our app called
Settings. Rather than just store settings data as a plain array on our Livewire component, we can attach associated behavior to this data with a convenient wrapper object or DTO like
Now you can freely use this object as a public property of your component like so:
And as you can see, changes to the component are persisted between requests because, with
Wireable, Livewire knows how to “dehydrate” and “re-hydrate” this property on your component.
If words like “hydrate” or “dehydrate” in the context of Livewire are fuzzy for you, give this post a quick read.
Array targeted loading indicators
In cases where you want a loading indicator to be scoped to ALL changes in an array, not just specific, singular, items in the array, you can now reference the array property itself.
For example, If you have two different Livewire properties, one is an array and the other is not, you may want to show a loading indicator for any changes made to the array and not to the other one.
In the above component, the loading indicator will only show when updates are being made to the
post property, not the
This is a better alternative to having to list out every single target like so:
Warn when multiple root elements are present
Livewire components can only have ONE root element. If two are present, Livewire fails silently causing lots of confusion for newcomers.
Now, Livewire will detect a second root element for a component and warn the user in the console.
Parsing HTML to detect multiple root elements in the backend is very hard and problematic. This is why we are not throwing a backend error, but instead throwing a warning on the front-end.
To make this possible, Livewire now adds a small HTML comment at the bottom of every component’s HTML so that the front-end can easily track the scope of any given component and detect more than one root element.
Private methods and props available via
Livewire currently exposes a
$this object inside your component’s Blade view. This way you have easy access to both properties and methods on your component object from inside your views.
Currently, you can only access PUBLIC properties and methods through
$this. Now, both protected and private methods and properties will be available on
$this, just as if it was an actual
A lesser-known feature of Livewire’s loading system is the
When appended to
.delay prevents the loading indicator from showing if the request is completed within 200ms.
This way you don’t get a loading indicator “blip” that can be jarring to users.
Although useful in its current state, often people want to configure the exact time delay of
You’d think it’s as simple as supporting time suffixes like other APIs in Livewire and Alpine do. For example, the logical API for this feature would be something like:
However, this is an extremely hard API to achieve in this case because of CSS selector constraints. Unlike other
wire:loading has secret special behavior. If you dig through the styles that Livewire adds to your page, you will notice something like this:
To avoid this, Livewire adds this CSS style that hides any
wire:loading element until Livewire initializes.
The problem is that it is currently impossible in CSS to make a selector with a wildcard in the attribute. Ideally, we’d be able to do something like this:
[wire:loading.*]. But unfortunately, that isn’t the world we live in.
So instead, we are going with pre-defined values for different
.delay modifiers. Here they are:
Multiple paginator support
In Livewire, you can add the
WithPagination trait to any component that uses Laravel’s pagination features and like magic, pagination will become SPA-like requiring no page re-loads.
However, the current system has a few flaws which have been addressed in v2.6. Most notably of which is support for multiple paginators.
Because Livewire hardcodes the
$page property inside the
WithPagination trait, there is no way to have two different paginators on the same page because each will be competing for the same property name in the query string of the URL bar.
Here’s an example of two different components that might exist on the same page. By giving the second one (the comments one) a name, Livewire will pick it up and handle everything accordingly.
Now in the query string, both paginators will be represented like so:
Support for redirect()->with()
Livewire supports redirecting from any action called within your component using the standard APIs you’re used to using from a controller.
However, because Livewire hijacks Laravel’s redirector with its own, it hasn’t supported extra niceties like
->with() which is used to attach flash data along with the redirect.
No more. Livewire now allows
->with() to be appended to your
See it in action:
protected $queryString feature allows you to easily and declaratively track data inside the query string of your app’s URL.
However, currently, when you track an array property in your query string, it looks yucky. For example, here’s an array stored in the query string currently:
Before this update, the query string in the URL bar would look like this:
Here’s what that snippet will look like now after v2.6:
Browser back-button cache config
Here’s the problem: Google Chrome caches the initial HTML received from the server when you load a page. When a user hits the back button after leaving that page, Chrome immediately loads the page based on its initial HTML without making a new network request.
This behavior is problematic for Livewire (and really any non-trivial front-end setup) because if, for example, a user starts making changes on a page, when the user hits the back button, they will see whatever the state of the initial component was, not the most up-to-date state.
Chrome has its bfcache feature behind a feature flag but it still doesn’t ship enabled with browsers.
Because Chrome is so popular and until this happens, Livewire has decided to disabled the cache system entirely so that when a user hits the. back button, the browser will fetch a completely fresh page with completely fresh state.
This of course will be a slightly slower experience, but in our experience, 99% of users and use cases would rather have state in-sync than instantaneous back button visits.
This option is now configurable via
livewire.back_button_cache if you disagree.
Blade component layout love
Livewire allows you to render components as entire pages by simply passing them into your route definition like so:
By default, Livewire looks for a Blade layout component called:
This is a sensible default for people using Laravel Jetstream or people who acknowledge this pattern as a general Laravel app convention.
However, when you configure your own layout there are a few gotchas that have been addressed:
PHP 8.0 now introduced support for union types (the ability to declare more than one type in a type hint).
However, Livewire hasn’t supported this for its own method dependency injection system.
For example, with this addition you can now use a union type for a
mount() method parameter:
This was a difficult problem to think through. There are lots of questions like: What is the expected behavior here? If a user doesn’t pass in a parameter to the component what should the type be? Should Livewire use the first type in the list? Should it just pass null? Should it error out?
We ended up going with “passing null”.
If you use a union type in a method dependency and Livewire has to figure out which class to resolve out of the container, it will just pass you null because that question is impossible to answer.
In most cases with union types, you would be explicitly passing the parameter into Livewire and everything will work as expected now.
Support adding/removing public properties on deploy
This is one of those sneaky little problems that many people have experienced and isn’t /technically/ a bug (but totally is because it causes people errors in their apps).
Here’s the situation: If you have a property on a Livewire component called
$posts and many of your users have a page open in their browser that uses this component, IF you remove this property from the component and re-deploy your app, all those users that haven’t refreshed their page will receive an error the next time they interact with that component.
The problem exists because Livewire is extremely strict about people tampering with Component data for security’s sake and when it sees a new or removed property it assumes it was a malicious action.
However, because we can assume that backend code changes are intentional, Livewire now supports the addition and subtraction of properties on a component at runtime.
I know I’ve personally encountered this problem after deploying an update to a Livewire app and getting new bug notifications for a day or two until everyone has refreshed their pages.
Support DateTimeImmutable and CarbonImmutable
Over time Livewire has added support for more and more PHP types to be stored as public properties on components.
Version 2.6 now includes support for public properties of the type
There it is folks
Those are all the significant additions to the Livewire project available in version 2.6.0.
There are a few more features and many more bug fixes included in the release. You can view the full release notes here.
Thanks for caring,
This content was originally published here.