composer require dvarilek/filament-table-select:^2.0.3
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.
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') ])
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() ])
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]
IfmaxItems(1)
is set to 1, radio-like selection gets enabled regardless of the relationship type.
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}"; }) ])
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) ])
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.
Configuring the table is really important, especially defining the table columns. Without explicitly defining table columns, you would be presented with an empty table.
use Dvarilek\FilamentTableSelect\Components\Form\TableSelect;use Filament\Tables\Columns\TextColumn;use Filament\Tables\Table; TableSelect::make('clients') ->relationship('clients', 'name') ->selectionTable(function (Table $table) { return $table ->heading('Active Clients') ->columns([ TextColumn::make('name') ]) ->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)
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); })
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)
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()
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.
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.
[!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.
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.
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)
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... })
[!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.
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)
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(); });}
composer test
Please refer to Package Releases for more information about changes.
This package is under the MIT License. Please refer to License File for more information