How to create a web app using Laravel Livewire
Livewire lets you render and update your HTML from the server side. It means you can write your front end in Laravel, and it saves you duplicating your application logic in the front end.
Compared with a clean REST API it feels inefficient to be passing all this HTML to the client, and it’s something we should keep in mind.
However picture a typical Dashboard application where users are constantly manipulating data stored in your database. Chances are you already have a chatty API that is passing lots of data back and forth. In this case Livewire could be a great option!
How to install Livewire
We will start with a fresh install of Laravel 8 connected to a PostgreSQL database. We can install livewire using composer:
composer require livewire/livewire
Livewire works closely with Laravel’s Blade templating engine. Each Livewire component is created with a Blade template used to render its HTML.
To use Livewire you need to add a couple of tags to your Blade layout template. Update the contents of the welcome.blade.php landing page as follows, with the @livewireStyles and @livewireScripts tags.
And that’s it! You can serve the app via Artisan and view the landing page in your browser.
php artisan serve
Making a Users table
Now let’s create a table where we can view and update a list of users.
Run your database migrations:
php artisan migrate
And use Artisan Tinker to create some dummy users:
php artisan tinker
User::factory()->count(100)->create();
Now we can use an Artisan command to create our first Livewire component.
php artisan make:livewire users-table
Livewire has created two new files for us, a Component and a blade template.
- app\Http\Livewire\UsersTable.php
- resources\views\livewire\users-table.blade.php
Update the users-table.blade.php template with a simple table.
As you can see we need to pass in an array of users for the $users variable. Update the UsersTable.php component file as follows:
The mount() method makes use of one of the Livewire hooks. These work in a similar way to the lifecycle hooks used in Angular, React or Vue.
When Livewire renders the view it gets all the public properties from the Component class and makes them available as variables to the Blade template. So it’s enough to set our public $users property and it will automatically get passed down to the view!
If you’re curious how this happens then take a look at the parent Component.php class from the Livewire codebase and you‘ll find a method called getPublicPropertiesDefinedBySubClass().
Finally let’s include the new component on our landing page. Add a <livewire:users-table /> tag to the body of welcome.blade.php.
Now if you reload the page in your browser you’ll see a basic table with the first ten user records.
The first thing we need to do is add pagination so we can browse through the table.
You’ll notice we cast the paginator’s links() to HTML. That’s because we can only pass numeric, string, array, null and boolean variables to the view via the public properties.
Then update the users-table.blade.php file with the pagination links HTML.
For the pagination links to look good we need to install Tailwind
npm install -D tailwindcss@latest postcss@latest autoprefixer@latest
Initialise the config file:
npx tailwindcss init
This generates a tailwind.config.js file, open it and update the contents of the purge array:
Import Tailwind into your resources/js/app.js file
Finally update the contents of your resources/css/app.css file to pull in the tailwind libraries:
And update your welcome.blade.php layout file to pull in the app.css file:
Now if you reload your site you will see we have a paginated table. Notice how it stores the page in the URL query string. That means people can bookmark or share a link to a specific page of your table.
If you click between the tabs notice that the whole page refreshes. There’s a package called Turbolinks which lets us refresh the table without a page load. In Livewire 2 we need to pull in Turbolinks via the CDN.
Add this line to the <head> of your welcome.blade.php file:
<script src=”https://cdn.jsdelivr.net/gh/livewire/turbolinks@v0.1.x/dist/livewire-turbolinks.js" data-turbolinks-eval=”false” data-turbo-eval=”false”></script>
Then we need to update our UsersTable.php component to do things the Livewire way:
Notice we pull in the WithPagination trait from Livewire which allows us to use Turbolinks to jump between the pages of the table.
We can use the view() method to pass Classes to the view, in this case the result of the paginate() call which is a LengthAwarePaginator.
Then update your users-table.blade.php file to use the links directly from the paginator:
This is looking great! If you reload the page take a look at your network tab whilst clicking between the pages of the table. Notice how each click generates a single call to a livewire/message/users-table route and pulls in the updated HTML changes to the DOM.
How Livewire pagination works
It’s helpful to have an idea how this works under the hood. If you inspect one of the pagination link buttons in your browser dev tools you’ll see it includes a tag that looks like this:
wire:click=“gotoPage(2)”
This is our first Livewire action. The wire:click action listens for the user to click on the HTML element and then calls a method from the Livewire component. As you can see you can pass a variable — in this case the page number.
Column Sorting
Next we can use the wire:click action to let us sort the table. Update your UsersTable component with this code:
Here the handleSortBy($key) method handles when the user clicks on a table header. If the table is already sorted by the given column, then it reverses the direction. Otherwise it sorts by the new column key.
In the sortBy($key) function we also reset the page by calling a gotoPage() method from the WithPagination trait.
Finally we simply add an ->orderBy() call to the query in the render() method to actually sort the data we read from the database.
Here’s our updated code for the users-table.blade.php file. We simply added wire:click handlers to each of the column headers:
Now if you reload your app you’ll be able to sort any of the columns!
URL Query Strings
This is taking shape but you might have noticed we lost the query strings in the URL. Luckily Livewire makes it easy to handle query strings. Just add a variable called $queryString to the component:
How to add a Search
Now say we want to be able to search the table by either the ‘name’ or ‘email’ fields. We can add some properties and a handleSearchBy() method to the UsersTable component:
In the render() method we check the $this->search and $this->searchKey variables are set, and then use a where clause to search our table.
Here’s our updated users-table.blade.php:
We used wire:model to bind the search input’s value to the $name or $email variables on the component.
Reload the page and you will now be able to search your table!
Styling with Tailwind
At this point it would be great to style our table. We can use Tailwind classes to quickly get our UI into shape.
Update your users-table.blade.php file:
Also update your UsersTable.php file to include new getSortSymbol() and clearSearch() methods:
Now if you reload the table is looking much better with some styling!
Refactoring to Components
Now the table is looking decent it’s time to refactor our code.