Create a select filter with a default value
A typed Nova 5 select filter for an order status column, with a default selection and a reusable variant that takes the column name as a constructor argument.
- Nova
- 5.x
- Published
- Reading time
- 2 min
Most admin lists need a quick way to narrow records by status. In Nova that is a select filter: a class with an apply() method that modifies the query and an options() method that returns the choices.
Generate the filter
php artisan nova:filter OrderStatus
The filter class
<?php namespace App\Nova\Filters; use Illuminate\Contracts\Database\Eloquent\Builder; use Laravel\Nova\Filters\Filter; use Laravel\Nova\Http\Requests\NovaRequest; class OrderStatus extends Filter { public $component = 'select-filter'; public function apply(NovaRequest $request, Builder $query, mixed $value): Builder { return $query->where('status', $value); } public function options(NovaRequest $request): array { return [ 'Pending' => 'pending', 'Paid' => 'paid', 'Shipped' => 'shipped', 'Cancelled' => 'cancelled', ]; } public function default() { return 'paid'; } }
Note the direction of the options() array: the label is the key and the stored value is the array value. Swapping them is the most common reason a filter shows the wrong text or matches nothing.
default() preselects an option when the index loads, so the list opens on paid orders. Users can still pick a different status in the filter menu.
Register the filter on the resource
use Laravel\Nova\Http\Requests\NovaRequest; public function filters(NovaRequest $request): array { return [ new Filters\OrderStatus, ]; }
A reusable filter for any status column
If several resources filter on a status column with different names, pass the column into the constructor instead of copying the class:
<?php namespace App\Nova\Filters; use Illuminate\Contracts\Database\Eloquent\Builder; use Laravel\Nova\Filters\Filter; use Laravel\Nova\Http\Requests\NovaRequest; class StatusFilter extends Filter { public $component = 'select-filter'; public function __construct( protected string $column = 'status', protected array $statuses = [], ) {} public function apply(NovaRequest $request, Builder $query, mixed $value): Builder { return $query->where($this->column, $value); } public function options(NovaRequest $request): array { return $this->statuses; } public function key(): string { return 'status_filter_'.$this->column; } }
public function filters(NovaRequest $request): array { return [ new Filters\StatusFilter('payment_status', [ 'Open' => 'open', 'Paid' => 'paid', ]), ]; }
Overriding key() gives each instance its own key. Without it, two instances of the same filter class on one resource would share a key and overwrite each other's selection.