Laravel Livewire: 14 Tips & Tricks
Published on by PovilasKorop
Laravel Livewire is a great tool to achieve dynamic behavior on the page, without directly writing JavaScript code. And, like any tool, it has a lot of "hidden gems", both in its official docs, and practical extra tips provided by developers. I decided to compile some of them in this article. Let's get into it!
1. No render() needed
A typical render()
method looks something like this:
// app/Http/Livewire/PostsShow.phpclass PostsShow extends Component{ public function render() { return view('livewire.posts-show'); }}
But if your render()
method is just a one-line to render the default view, you may delete that render()
method from the component and it will all still work, loading the default render()
from the vendor's method.
class PostsShow extends Component{ // This empty component will still work and load the Blade file}
2. Components in Subfolders
If you want to generate a component in a subfolder, like app/Http/Livewire/Folder/Component.php
, you have two ways how to do it:
php artisan make:livewire Folder/Component
or
php artisan make:livewire folder.component
Notice that the first way is with the first letter uppercase, and the second way is lowercase. In both cases, there will be two files generated:
- app/Http/Livewire/Folder/Component.php
- resources/views/livewire/folder/component.blade.php
The subfolders will be created automatically if they don't exist.
3. Components in non-default Folder
If you use some external package with Livewire components, you may have your Livewire component in a different folder than the default app/Http/Livewire
. Then, you may need to bind its name to the actual location.
Typically, it's done in app/Providers/AppServiceProvider.php
(or in any service provider) method boot()
:
class AppServiceProvider extends ServiceProvider{ public function boot() { Livewire::component('shopping-cart', \Modules\Shop\Http\Livewire\Cart::class); }}
4. Easily Rename or Move Components
If you made a typo while generating the component with make:livewire
, don't worry. You don't need to rename two files manually, there's a command for that.
For example, if you wrote php artisan make:livewire Prduct
, but instead you want "Product", and also decided to put it into a subfolder, you can follow up with this command:
php artisan livewire:move Prduct Products/Show
The result will be this:
COMPONENT MOVED CLASS: app/Http/Livewire/Prduct.php => app/Http/Livewire/Products/Show.phpVIEW: resources/views/livewire/prduct.blade.php => resources/views/livewire/products/show.blade.php
5. Change Default Component Templates
Livewire components are generated using the default templates, so-called "stubs". They are hidden away in the "vendor" folder of the Livewire package, but you can publish them and edit them according to your needs.
Run this command:
php artisan livewire:stubs
You will find a new folder /stubs
with a few files.
Example of a stubs/livewire.stub
:
<?php namespace [namespace]; use Livewire\Component; class [class] extends Component{ public function render() { return view('[view]'); }}
For example, if you want to generate the components without the render()
method, just remove it from the stub file, and then each time you run php artisan make:livewire Component
, it will take the template from your updated public stub.
6. Don't Create a Method Just to Set Value
If you have a click event that would set some value of some property, you may do something like this:
<button wire:click="showText">Show</button>
And then
class Show extends Component{ public $showText = false; public function showText() { $this->showText = true; }}
But actually, you can assign a new value to the Livewire property directly from your Blade file, without having a separate method in the Livewire component.
Here's the code:
<button wire:click="$set('showText', true)">Show</button>
So, you call the $set
and provide two parameters: your property name and the new value.
7. Step Even Further: Set True/False Value Easily
Following up on the last tip, if your property is a boolean variable with true/false values, and you want to have a show/hide button, you can do something like this:
<button wire:click="$toggle('showText')">Show/Hide</button>
Notice: I would personally avoid using Livewire for such simple toggle effects because it adds the additional request to the server.
Instead, it's better to use JavaScript for this, like Alpine.js:
<div x-data="{ open: false }"> <button @click="open = true">Expand</button> <span x-show="open"> Content... </span></div>
8. Three Ways to Minimize Server Requests
One of the main criticism of Livewire is the fact that it does too many requests to the server. If you have wire:model
on the input field, each keystroke would potentially call the server to re-render the component. It's very convenient if you have some real-time effects, like "live search". But generally, server requests may be quite expensive, in terms of performance.
However, it's very easy to customize this behavior of wire:model
.
-
wire:model.debounce
: by default, Livewire waits for 150ms after the keystroke on the input, before performing the request to the server. But you can override it:<input type="text" wire:model.debounce.1000ms="propertyName">
-
wire:model.lazy
: by default, Livewire is listening for all events on the input, and then performs the server requests. By providing alazy
directive, you tell Livewire to listen only to thechange
event. It means that the user may keep typing and changing the value, and the server request will be fired only when the user clicks away from that field. -
wire:model.defer
: this will not fire the server requests on the change of the input. It will save the new value internally and will pass it to the next network request, which may come from other input fields or other button clicks.
9. Customize Validation Attributes
Livewire validation works very similarly to the Laravel validation engine, but with a few differences. In Laravel, if you want to customize the names of the attributes, you may define the attributes()
method in a Form Request class.
In Livewire, the approach is different. In the component, you need to define a property called $validationAttributes
and assign the array of key-value there:
class ContactForm extends Component{ protected $validationAttributes = [ 'email' => 'email address' ]; // ...
This is useful for common error messages, like "Field [XYZ] is required". By default, that XYZ is replaced with the field name, which may be not a human-friendly word, so it's worth replacing it for the error messages with something clearer.
10. Loading Indicators
Something that is described in the official documentation but quite rarely used, from what I've seen. If some action takes a while on the screen, it's worth showing some loading indicator, like a spinning gif, or just a text of "Loading data..."
In Livewire, it's very easy not only to implement but also to customize.
The most simple example of processing data: when the server request is made, it will show "Processing Payment..." text until the server request is finished and back with the result.
<div> <button wire:click="checkout">Checkout</button> <div wire:loading> Processing Payment... </div></div>
In practice, I like to show such loading indicators only if it takes a while. No point in re-rendering the DOM every time, in every possible case. What if we do it only if the request takes more than 500ms?
Easy:
<div wire:loading.delay.longer>...</div>
There are also possibilities to play around with CSS classes for loading states, attach them to specific actions, and more: read in the official docs.
11. Offline Indicator
Another documented but less known feature of Livewire is telling the user if their internet connection is lost. It can be beneficial if your application works with real-time data or multiple updates on the screen: you may blur some parts of the webpage and show the "offline" text.
It's as easy as this:
<div wire:offline> You are now offline.</div>
Also, as I mentioned, you may blur some elements, by assigning CSS classes, like this:
<div wire:offline.class="bg-red-300"></div>
12. Pagination with Bootstrap Framework
Similar to Laravel, Livewire uses pagination styling from the Tailwind framework, by default. Luckily, it's easy to override, just provide the different value to the property:
class ShowPosts extends Component{ use WithPagination; protected $paginationTheme = 'bootstrap';
You can check the available pagination designs directly in Livewire Github repository. While browsing that, I didn't find any information on whether the Bootstrap 4 or Bootstrap 5 version is used.
13. No Mount: Automatic Route-Model Binding
If you want to pass an object to the Livewire component, this is a typical way to do it, with the mount()
method:
class ShowPost extends Component{ public $post; public function mount(Post $post) { $this->post = $post; }}
Then, somewhere in Blade, you have @livewire('show-post', $post)
.
But did you know that if you provide a type-hint to the Livewire property, that route-model binding would happen automatically?
class ShowPost extends Component{ public Post $post;}
That's it, no need to have the mount()
method at all.
14. Delete Confirm Modal
If you have a "Delete" button and you want to call the confirm JavaScript modal before taking the action, this code wouldn't work correctly in Livewire:
<button wire:click="delete($post->id)" onclick="return confirm('Are you sure?')">Delete</button>
There are a few possible solutions to this, probably the most elegant is to stop the Livewire event before it is even happening:
<button onclick="confirm('Are you sure?') || event.stopImmediatePropagation()" wire:click="delete($post->id)">Delete</button>
That event.stopImmediatePropagation()
will stop the Livewire method from being called, if the confirmation result is false.
You may find a few other possible solutions in this Github issue discussion.
That's it, less-known Livewire features and small tips. Hope it was useful!