dvarilek / filament-table-select
Laravel Filament form component for selecting related records with a table.
Requires
- php: ^8.2|^8.3|^8.4
- dvarilek/livewire-closure-synthesizer: ^1.1
- filament/filament: ^3.0
- spatie/laravel-package-tools: ^1.18
Requires (Dev)
- orchestra/testbench: ^8.0|^9.0
- pestphp/pest: ^2.31|^3.0.0
- pestphp/pest-plugin-livewire: ^3.0
- phpstan/phpstan: ^2.1
README
Installation
composer require dvarilek/filament-table-select:^2.0
Overview
This package introduces a new Form component that acts as a replacement for the Select field by allowing users to select related records from a full-fledged Filament table through a relationship.
Naturally, using a table for selection provides much greater context and clarity, as users can interact with it like any other Filament table. The table can be fully customizable.
filament-table-select-demo.mp4
Getting Started
Even though TableSelect doesn't extend Select field directly, it borrows some functionality from it.
First, configure the relationship and title attribute using the relationship()
method, which works the same way as in
Filament's standard Select field. This method sets up a BelongsTo
relationship to automatically retrieve options,
where the titleAttribute
specifies the column used to generate labels for each option.
use Dvarilek\FilamentTableSelect\Components\Form\TableSelect; $form ->schema([ TableSelect::make('clients') ->relationship('clients', 'name') ])
single-select.mp4
Multi Selection
The multiple()
method enables to use a belongsToMany()
relationship, which allows to select and associate multiple
records.
use Dvarilek\FilamentTableSelect\Components\Form\TableSelect; $form ->schema([ TableSelect::make('clients') ->relationship('clients', 'name') ->multiple() ])
multi-select.mp4
Selected Items Validation
You can validate the minimum and maximum number of items that you can select in a multi-select by
setting the minItems()
and maxItems()
methods:
use Dvarilek\FilamentTableSelect\Components\Form\TableSelect; $form ->schema([ TableSelect::make('clients') ->relationship('clients', 'name') ->multiple() ->minItems(1) ->maxItems(3) ])
Note
If maxItems(1)
is set to 1, radio-like selection gets enabled regardless of the relationship type.
Customizing Selected Options
Label Configuration
The TableSelect field enables for customization of selected options and their badges.
To customize the color of selected options, use the optionColor()
method:
use Dvarilek\FilamentTableSelect\Components\Form\TableSelect; $form ->schema([ TableSelect::make('clients') ->relationship('clients', 'name') ->multiple() ->optionColor('success') ])
To customize the icon of selected options, use the optionIcon()
method:
use Dvarilek\FilamentTableSelect\Components\Form\TableSelect; $form ->schema([ TableSelect::make('clients') ->relationship('clients', 'name') ->multiple() ->optionIcon('heroicon-o-bell') ])
Even though both optionColor()
and optionIcon()
methods accept callbacks, they cannot work with the given record instance.
This is done for performance reasons, so all selected options are not loaded into memory on each request.
To customize the colors of selected options while being able to access the Eloquent model instance,
use the getOptionColorFromRecordUsing()
method.
use Dvarilek\FilamentTableSelect\Components\Form\TableSelect; $form ->schema([ TableSelect::make('clients') ->relationship('clients', 'name') ->multiple() ->getOptionColorFromRecordUsing(function (Client $record) { return match ($record->status) { 'lead' => 'primary', 'closed' => 'success', 'lost' => 'gray', 'active' => 'danger', default => 'primary' }; }) ])
To customize the icons of selected options while being able to access the Eloquent model instance,
use the getOptionIconFromRecordUsing()
method.
use Dvarilek\FilamentTableSelect\Components\Form\TableSelect; $form ->schema([ TableSelect::make('clients') ->relationship('clients', 'name') ->multiple() ->getOptionIconFromRecordUsing(function (Client $record) { return match ($record->status) { 'lead' => 'heroicon-o-light-bulb', 'closed' => 'heroicon-o-check-circle', 'lost' => 'heroicon-o-x-circle', 'active' => 'heroicon-o-bolt', default => 'heroicon-o-question-mark-circle', }; }) ])
To customize the labels of selected options while being able to access the Eloquent model instance,
use the getOptionLabelFromRecordUsing()
method.
use Dvarilek\FilamentTableSelect\Components\Form\TableSelect; $form ->schema([ TableSelect::make('clients') ->relationship('clients', 'name') ->multiple() ->getOptionLabelFromRecordUsing(function (Client $record) { return "{$record->first_name} {$record->last_name} - {$record->status}"; }) ])
Other Configuration Options
To customize the size of selected option badges, use the optionSize()
method:
use Dvarilek\FilamentTableSelect\Components\Form\TableSelect; use Filament\Support\Enums\ActionSize; $form ->schema([ TableSelect::make('clients') ->relationship('clients', 'name') ->multiple() ->optionSize(ActionSize::Large) ])
To customize the size of selected option badges, use the optionIconSize()
method:
use Dvarilek\FilamentTableSelect\Components\Form\TableSelect; use Filament\Support\Enums\IconSize; $form ->schema([ TableSelect::make('clients') ->relationship('clients', 'name') ->multiple() ->optionIconSize(IconSize::Large) ])
Selection Table
Selection Table Configuration
You can configure the Selection table by passing a closure into the selectionTable()
method, this is where
you can add columns, remove actions, modify the table's query etc.
use Dvarilek\FilamentTableSelect\Components\Form\TableSelect; use Filament\Tables\Table; TableSelect::make('clients') ->relationship('clients', 'name') ->selectionTable(function (Table $table) { return $table ->heading('Active Clients') ->actions([]) ->modifyQueryUsing(fn (Builder $query) => $query->where('status', 'active')); })
Additionally, If you wish to customize the Selection Table Livewire component, you can access it as the second argument:
use Dvarilek\FilamentTableSelect\Components\Livewire\SelectionTable; use Filament\Tables\Table; ->selectionTable(function (Table $table, SelectionTable $livewire) { // ... })
To use an already defined table from a Filament Resource, use the tableLocation()
method:
use Dvarilek\FilamentTableSelect\Components\Form\TableSelect; TableSelect::make('clients') ->relationship('clients', 'name') ->tableLocation(ClientResource::class)
Selection Action
Selection Action Configuration
The selection action and its modal, where the table is contained, can be configured using the selectionAction()
method:
use Dvarilek\FilamentTableSelect\Components\Form\TableSelect; use Filament\Forms\Components\Actions\Action; TableSelect::make('clients') ->relationship('clients', 'name') ->selectionAction(function (Action $action) { return $action ->icon('heroicon-o-user-plus') ->modalHeading('Select Clients') ->slideOver(false); })
Selection Action Position
By default, the selection action is displayed in the left bottom corner. To change its position,
use the selectionActionAlignment()
method:
use Dvarilek\FilamentTableSelect\Components\Form\TableSelect; use Filament\Forms\Components\Actions\Action; use Filament\Support\Enums\Alignment; TableSelect::make('clients') ->relationship('clients', 'name') ->selectionAction(function (Action $action) { return $action ->icon('heroicon-o-user-plus') ->modalHeading('Select Clients') ->slideOver(false); }) ->selectionActionAlignment(Alignment::End)
Or provide an optional parameter directly in the selectionAction()
method:
use Filament\Support\Enums\Alignment; ->selectionAction(alignment: Alignment::Center)
Opening Selection Modal On Click
If you with to hide this action and open the modal by clicking on the Field directly, use the
triggerSelectionActionOnInputClick()
method:
use Dvarilek\FilamentTableSelect\Components\Form\TableSelect; use Filament\Forms\Components\Actions\Action; TableSelect::make('clients') ->relationship('clients', 'name') ->selectionAction(function (Action $action) { return $action ->icon('heroicon-o-user-plus') ->modalHeading('Select Clients') ->slideOver(false); }) ->triggerSelectionActionOnInputClick()
open-on-click.mp4
Or provide an optional parameter directly in the selectionAction()
method:
->selectionAction(shouldTriggerSelectionActionOnInputClick: true)
Note
Having this feature enabled still requires the selection action itself to be visible, because it needs to get mounted.
Confirmation action
Selection Confirmation
By default, the component's state is automatically updated as records are selected.
To require a confirmation of the selection, use the requiresSelectionConfirmation()
method:
use Dvarilek\FilamentTableSelect\Components\Form\TableSelect; TableSelect::make('clients') ->relationship('clients', 'name') ->requiresSelectionConfirmation();
This prevents automatic state updates and adds a confirmation action to the modal. Only when this action is clicked will the form component's state get updated.
selection-confirmation.mp4
Important
If you're concerned about performance, especially when updating the state would load a large number of models (e.g., when using one of the getOptionFromRecord methods), consider enabling this feature.
Closing After Selection
After confirmation, the modal closes by default. To keep it open, use the shouldCloseAfterSelection()
:
use Dvarilek\FilamentTableSelect\Components\Form\TableSelect; TableSelect::make('clients') ->relationship('clients', 'name') ->requiresSelectionConfirmation() ->shouldCloseAfterSelection(false);
Or provide an optional parameter directly in the requiresSelectionConfirmation()
method:
->requiresSelectionConfirmation(shouldCloseAfterSelection: false)
Note
Obviously, this only takes effect when selection confirmation is enabled.
Selection Action Position
By default, the confirmation action is positioned in the bottom left corner of the modal. To change its position use the
confirmationActionPosition()
method:
use Dvarilek\FilamentTableSelect\Components\Form\TableSelect; use Dvarilek\FilamentTableSelect\Enums\SelectionModalActionPosition; TableSelect::make('clients') ->relationship('clients', 'name') ->requiresSelectionConfirmation() ->confirmationActionPosition(SelectionModalActionPosition::TOP_LEFT);
Or provide an optional parameter directly in the requiresSelectionConfirmation()
method:
use Dvarilek\FilamentTableSelect\Enums\SelectionModalActionPosition; ->requiresSelectionConfirmation(confirmationActionPosition: SelectionModalActionPosition::TOP_LEFT)
Creating New Records
Create Option Action
In a standard Select field, if users can’t find the record they need, they can create and associate a
new one on using the createOptionAction()
. - Official Filament Documentation
The TableSelect borrows this exact functionality and displays the create option action in the selection modal. To configure this action you can use the following methods:
use Dvarilek\FilamentTableSelect\Components\Form\TableSelect; TableSelect::make('clients') ->relationship('clients', 'name') ->createOptionForm(ClientResource::form(...)) ->createOptionUsing(function (array $data) { // Create related record using... }) ->createOptionAction(function () { // Configure the action... })
create-option.mp4
Important
When a new record is created, it's automatically selected in the table. If this newly created record exceeds the selection limit, the record naturally won't be selected. Obviously, in single-selection mode, the new record will replace the old one.
Create Option Action Position
By default, the create option action is positioned in the top right corner of the modal. To change its position use the
createOptionActionPosition()
method:
use Dvarilek\FilamentTableSelect\Components\Form\TableSelect; use Dvarilek\FilamentTableSelect\Enums\SelectionModalActionPosition; use Filament\Forms\Form; TableSelect::make('clients') ->relationship('clients', 'name') ->createOptionForm(fn (Form $form) => ClientResource::form($form)) ->createOptionActionPosition(SelectionModalActionPosition::TOP_LEFT)
Advanced
To globally configure all TableSelect component instances, use the configureUsing()
method in you application's
Service Provider boot method:
use Dvarilek\FilamentTableSelect\Components\Form\TableSelect; public function boot(): void { TableSelect::configureUsing(static function (TableSelect $tableSelect): void { $tableSelect->requiresSelectionConfirmation(); }); }
Testing
composer test
Changelog
Please refer to Package Releases for more information about changes.
License
This package is under the MIT License. Please refer to License File for more information