As a developer working with Laravel and Filament, you’ve probably encountered the need to provide more advanced filtering capabilities for your users. By default, Filament’s table filters are quite basic, and often require custom code or workarounds to implement even simple features like date range selection or dropdown menus.
If you’re tired of digging through Filament’s documentation or scouring online forums for solutions, this tutorial is for you. You’ll build a custom table filter from scratch, complete with its own configuration options and integration into your existing Filament resources. Specifically, by the end of this guide, you’ll have created a custom date range filter that works seamlessly with your Eloquent model’s data, and be able to apply it to any resource in your application.
Setting Up Filament and the Required Packages
To start building a custom table filter for Filament, you’ll need to set up the necessary packages and create a new project or update an existing one.
First, ensure you have Composer installed on your system. You can verify this by running composer --version in your terminal.
Next, create a new Laravel project using Composer:
composer create-project --prefer-dist laravel/laravel filament-table-filter-example
Alternatively, if you already have an existing Laravel project, navigate to the root directory and run composer require instead:
cd my-existing-laravel-project
composer require laravel/filament:2.0.*
Now that we have the base application set up, let’s install Filament itself using Composer. Open your terminal and navigate to the project root directory:
composer require filament/auth filament/tables
This will install the necessary packages for Filament, including authentication and table features.
Make sure you’re in the correct directory by checking the project name listed above the command prompt or terminal window. You should see something like (filament-table-filter-example)$ indicating you’re currently working with your new Laravel project.
Verify that everything installed correctly by running composer show -i. This will display a list of all packages and their versions in your project.
At this point, you’ve set up the necessary tools to build your custom table filter for Filament.
Creating a Custom Table Filter Component
To create a custom table filter component in Filament, we’ll first create a new PHP file within the app/Components directory. This will house our custom filter component.
// app/Components/TableFilterComponent.php
namespace App\Components;
use Filament\Forms\Components\Component;
use Filament\Forms\Components\Select;
class TableFilterComponent extends Component
{
protected static ?string $view = 'components.table-filter';
public function options(): array
{
return [
'filter' => Select::make('filter')
->options([
'equals' => 'Equals',
'not_equals' => 'Not Equals',
])
->searchable(),
];
}
}
In the code above, we define a TableFilterComponent class that extends Filament’s built-in Component. We specify the component view as components.table-filter, which we’ll create in the next step.
Next, let’s create a Blade template for our component. In this case, we’re using the same name as specified in the component file (table-filter.blade.php).
// resources/views/components/table-filter.blade.php
<x-filament::card>
<x-slot name="header">
{{ __('Filter') }}
</x-slot>
{{ $form->make()->schema([
$form->components()->filter(),
]) }}
</x-filament::card>
This template defines a basic card layout for our filter.
Defining the Filter Logic and Configuration
In this step, we’ll define the filter logic and configure it to work seamlessly with our custom table filter component. Create a new file FilterLogic.php within your app/Services directory:
// app/Services/FilterLogic.php
namespace App\Services;
use Filament\Tables\Filters\BooleanFilter;
use Filament\Tables\Filters\EnumFilter;
use Illuminate\Support\Facades\DB;
class FilterLogic
{
public function getFilters(): array
{
return [
BooleanFilter::make('active', 'Active')
->query(function ($query, $value) {
if ($value === true) {
$query->where('is_active', 1);
} elseif ($value === false) {
$query->where('is_active', 0);
}
})
->default(false),
EnumFilter::make('status')
->enum([
'pending' => 'Pending',
'in_progress' => 'In Progress',
'completed' => 'Completed',
])
->default('pending'),
];
}
public function applyFilters($query, $filters)
{
foreach ($filters as $filter) {
if (isset($filter['active'])) {
if ($filter['active']) {
$query->where('is_active', 1);
} else {
$query->where('is_active', 0);
}
}
if (isset($filter['status'])) {
$query->where('status', $filter['status']);
}
}
}
}
Here, we’ve defined two filters: BooleanFilter for the active column and EnumFilter for the status column. The filter logic is applied to the query in the applyFilters method. This will ensure that our custom table filter works as expected when used within the Filament resource.
Next, we’ll implement this filter logic into our custom table filter component.
Implementing the Filter in the Filament Resource
Now that our custom filter is defined and configured, it’s time to implement it within a Filament resource. This is typically done by creating a new Filters class within the relevant Filament resource’s directory.
Let’s create a Filters class for our example model (App\Models\User.php) in the Resources\Pages\Users\Components namespace:
// app/Resources/ Pages/Users/Components/Filters.php
namespace App\Resources\Pages\Users\Components;
use Filament\Forms\Concerns\InteractsWithForms;
use Filament\Tables\Filters\FilterInterface;
use Illuminate\Support\Collection;
class Filters implements FilterInterface
{
use InteractsWithForms;
public static function configure(): void
{
self::make('name')
->schema([
'type' => 'text',
'searchable' => true,
]);
}
}
Next, we need to modify our UsersTable class to include the filter we’ve just created. This can be done by adding a new method that specifies the filters for this resource:
// app/Resources\Pages\Users\Resources\UsersTable.php
namespace App\Resources\Pages\Users\Resources;
use Filament\Tables\Table;
use Illuminate\Support\Collection;
use App\Resources\Pages\Users\Components\Filters;
class UsersTable extends Table
{
protected static string $recordPath = 'users';
protected function configureTable(): void
{
// Existing configuration...
}
public function filters(): Collection
{
return [
Filters::class,
];
}
}
With these modifications in place, the filter should now be visible on your Filament user list page.
Configuring the Filter to Work with Your Model’s Data
To make our custom filter work seamlessly with your model’s data, we need to configure it to fetch and display the correct data from the database.
Firstly, let’s update the App\Models\YourModel.php file (replace YourModel with the actual name of your Eloquent model). We’ll add a new method called searchableColumns that returns an array of column names that should be searchable.
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Filament\Facades\Filament;
class YourModel extends Model
{
public function searchableColumns(): array
{
return [
'name',
'email',
// Add more columns as needed
];
}
}
Next, we’ll update our filter component to fetch the data from the model. In app/Filament/CustomTableFilter.php, replace the existing logic with the following code:
namespace App\Filament\Components;
use Filament\Facades\Filament;
use Illuminate\Support\Collection;
class CustomTableFilter extends Component
{
public function handleSearch(): void
{
$query = YourModel::query();
foreach ($this->getState() as $column => $value) {
if (in_array($column, $this->getSearchableColumns())) {
$query->where($column, 'like', '%' . $value . '%');
}
}
$this->setPage('table.table', Filament::resources()->make(YourModel::class));
}
private function getSearchableColumns(): array
{
return app(YourModel::class)->searchableColumns();
}
}
This will ensure our filter is fetching the correct data from your model and displaying it in the table.
Testing the Custom Table Filter in Action
To verify that our custom table filter is working correctly, we’ll need to test it on a real-world dataset. For this purpose, let’s assume we have a users table with several records.
Firstly, navigate to your project root and run the following command to seed the database with some sample data:
php artisan db:seed --class=UsersTableSeeder
This will populate our users table with about 10 sample records. Now that we have some data, let’s go back to our application and access the Filament resource where we implemented our custom filter.
In your browser, navigate to the URL of your application, followed by /admin/users, which should open the Users resource page in Filament. On this page, you’ll find a table displaying all users with their respective details.
Look for the Status column and verify that our custom filter is working as expected. We can apply different filters using the dropdown menu next to the Status label. For example, if we select Active, the table should only display active users.
// In resources/views/filament/resources/Users/Index.blade.php
<x-filament::pagelet>
@livewire('status-filter')
</x-filament::pagelet>
This is a basic test to ensure that our custom filter is functioning as intended. With this in place, we can now customize the appearance and behavior of our table filter as needed.
With our custom filter working correctly, we’re one step closer to fine-tuning it according to our application’s specific requirements.
Customizing the Filter Appearance and Behavior
Now that our custom table filter is up and running, it’s time to make some adjustments to its appearance and behavior. We can do this by using various Filament features such as modifying the config method in our filter class or overriding the component templates.
Let’s say we want to change the default label for our filter from “Filter” to something more descriptive like “Search by Name”. We can do this by adding a new line to the config method:
public static function config(): array
{
return [
// ...
'label' => 'Search by Name', // Change the default label
// ...
];
}
Alternatively, we can override the component template for our filter. This will allow us to completely customize the layout and design of the filter. To do this, we need to create a new directory views in our package root and add an index.blade.php file containing the custom template:
<!-- views/index.blade.php -->
<div>
<h2>{{ $view['config']['label'] }}</h2>
<!-- Custom filter form -->
<form>
<!-- ... -->
</form>
</div>
With these changes, our custom table filter now has a more descriptive label and a customized layout. We can further customize the behavior of our filter by using Filament’s hooks or modifying the underlying code.
Our tutorial is now complete! With this final section, we’ve covered all aspects of creating a custom table filter with Filament and have been able to customize its appearance and behavior.
Frequently Asked Questions
What are the system requirements for setting up Filament and creating a custom table filter?
You need to have Composer installed on your system. You can verify this by running composer --version in your terminal.
How do I troubleshoot common errors when installing Filament packages using Composer?
Check the project directory to ensure you’re in the correct location and run composer show -i to display a list of all packages and their versions. This can help identify any issues with package installation.
Is it possible to use an alternative approach, such as using Laravel’s built-in filtering features instead of creating a custom table filter?
Yes, you can use Laravel’s built-in filtering features, but this tutorial focuses on creating a custom table filter for Filament. Using the built-in features might require more code and customization than using a custom filter.
What are some common pitfalls to avoid when implementing date range selection in a custom table filter?
Make sure to use the correct Eloquent model and database column names when defining the date range filter, as incorrect column names can lead to errors or unexpected results.
