Have you ever needed a checkbox-based filter for a list, like in e-shop sidebars? In this tutorial, we will use Livewire to build this step-by-step and update the products list without page refresh.

Notice: the link to the repository will be at the end of the tutorial.
We will use Livewire features like Events and Lifecycle Hooks to achieve the end result.
So let's dive in!
Laravel Project Preparation
For this demo, we'll use our own Laravel Breeze Pages Skeleton which will give us a Breeze-like layout but with a public page for the products list.
As you saw in the screenshot above, we will filter by three criteria:
- Price (within the Product itself)
- Category (a
belongsTorelationship) - Manufacturer (a
belongsTorelationship)
So first, we need Models and Migrations for all of them.
php artisan make:model Category -mphp artisan make:model Manufacturer -mphp artisan make:model Product -m
database/migrations/xxxx_create_categories_table.php:
public function up(): void{ Schema::create('categories', function (Blueprint $table) { $table->id(); $table->string('name'); $table->timestamps(); });}
app/Models/Category.php:
class Category extends Model{ protected $fillable = [ 'name', ]; public function products(): HasMany { return $this->hasMany(Product::class); }}
database/migrations/xxxx_create_manufacturers_table.php:
public function up(): void{ Schema::create('manufacturers', function (Blueprint $table) { $table->id(); $table->string('name'); $table->timestamps(); });}
app/Models/Manufacturer.php:
class Manufacturer extends Model{ protected $fillable = [ 'name', ]; public function products(): HasMany { return $this->hasMany(Product::class); }}
database/migrations/xxxx_create_products_table.php:
public function up(): void{ Schema::create('products', function (Blueprint $table) { $table->id(); $table->string('name'); $table->text('description'); $table->decimal('price'); $table->foreignId('category_id')->constrained(); $table->foreignId('manufacturer_id')->constrained(); $table->timestamps(); });}
app/Models/Manufacturer.php:
class Product extends Model{ protected $fillable = [ 'name', 'description', 'price', 'category_id', 'manufacturer_id', ]; public function category(): BelongsTo { return $this->belongsTo(Category::class); }}
Livewire Components
Next, after the installation of Livewire itself, we will need two Livewire components:
- One to show the products
- And another one for a sidebar with filters
When we click on any filter in the sidebar, the event will be sent to the Products component.
php artisan make:livewire Productsphp artisan make:livewire Sidebar
First, let's just show filters and products, and later we will actually make filters work.
Here's how to add Livewire components in the Blade...
Premium Members Only
This advanced tutorial is available exclusively to Laravel Daily Premium members.
Already a member? Login here
Premium membership includes:
Comments & Discussion
Very good, BUT for this (& similar) use case one should probably consider investing the time in Scout (using Algolia or Meilisearch) and InstantSearch.js for scalable UI/UX.
See for example InstantSearch.js widget showcase which is this exact example.
Thank you for this tutorial, i have onequestion please, How to add pagination for this Filter?
Well, it's not easy to answer in a comment. But basically, you just change
Product::withFilters(...)->get()toProduct::withFilters(...)->paginate()and add the pagination links.You may also use Livewire pagination: https://laravel-livewire.com/docs/2.x/pagination
I have a problem when I change pages with pagination, the filter no longer works, the display returns to the start
You add
use WithPagination;on the component Livewire?I added it but still the same problem
In the Livewire component
app/Http/Livewire/Products.phpchangeto
and add
$this->resetPage();to methodsetSelected