Select column
En esta página
- Introduction#
- Enabling the JavaScript select#
- Searching options#
- Returning custom search results#
- Setting a custom loading message#
- Setting a custom no search results message#
- Setting a custom search prompt#
- Setting a custom searching message#
- Tweaking the search debounce#
- Integrating with an Eloquent relationship#
- Searching relationship options across multiple columns#
- Preloading relationship options#
- Excluding the current record#
- Customizing the relationship query#
- Customizing the relationship option labels#
- Remembering options#
- Allowing HTML in the option labels#
- Wrap or truncate option labels#
- Disable placeholder selection#
- Disabling specific options#
- Limiting the number of options#
- Validation#
- Valid options validation (in rule)#
- Lifecycle hooks#
- Security#
- Authorization#
import Aside from "@components/Aside.astro" import AutoScreenshot from "@components/AutoScreenshot.astro" import UtilityInjection from "@components/UtilityInjection.astro"
Introduction#
The select column allows you to render a select field inside the table, which can be used to update that database record without needing to open a new page or a modal.
You must pass options to the column:
use Filament\Tables\Columns\SelectColumn;
SelectColumn::make('status')
->options([
'draft' => 'Draft',
'reviewing' => 'Reviewing',
'published' => 'Published',
])
Enabling the JavaScript select#
By default, Filament uses the native HTML5 select. You may enable a more customizable JavaScript select using the native(false) method:
use Filament\Tables\Columns\SelectColumn;
SelectColumn::make('status')
->options([
'draft' => 'Draft',
'reviewing' => 'Reviewing',
'published' => 'Published',
])
->native(false)
native() method also accepts a function to dynamically calculate it. You can inject various utilities into the function as parameters.
Searching options#
You may enable a search input to allow easier access to many options, using the searchableOptions() method:
use Filament\Tables\Columns\SelectColumn;
SelectColumn::make('author_id')
->label('Author')
->options(User::query()->pluck('name', 'id'))
->searchableOptions()
Optionally, you may pass a boolean value to control if the input should be searchable or not:
use Filament\Tables\Columns\SelectColumn;
SelectColumn::make('author_id')
->label('Author')
->options(User::query()->pluck('name', 'id'))
->searchableOptions(FeatureFlag::active())
searchableOptions() method also accepts a function to dynamically calculate it. You can inject various utilities into the function as parameters.
Returning custom search results#
If you have lots of options and want to populate them based on a database search or other external data source, you can use the getOptionsSearchResultsUsing() and getOptionLabelUsing() methods instead of options().
The getOptionsSearchResultsUsing() method accepts a callback that returns search results in $key => $value format. The current user's search is available as $search, and you should use that to filter your results.
The getOptionLabelUsing() method accepts a callback that transforms the selected option $value into a label. This is used when the form is first loaded when the user has not made a search yet. Otherwise, the label used to display the currently selected option would not be available.
Both getOptionsSearchResultsUsing() and getOptionLabelUsing() must be used on the select if you want to provide custom search results:
use Filament\Tables\Columns\SelectColumn;
SelectColumn::make('author_id')
->searchableOptions()
->getOptionsSearchResultsUsing(fn (string $search): array => User::query()
->where('name', 'like', "%{$search}%")
->limit(50)
->pluck('name', 'id')
->all())
->getOptionLabelUsing(fn ($value): ?string => User::find($value)?->name),
getOptionLabelUsing() is crucial, since it provides Filament with the label of the selected option, so it doesn't need to execute a full search to find it. If an option is not valid, it should return null.
Setting a custom loading message#
When you're using a searchable select or multi-select, you may want to display a custom message while the options are loading. You can do this using the optionsLoadingMessage() method:
use Filament\Tables\Columns\SelectColumn;
SelectColumn::make('author_id')
->optionsRelationship(name: 'author', titleAttribute: 'name')
->searchableOptions()
->optionsLoadingMessage('Loading authors...')
optionsLoadingMessage() method also accepts a function to dynamically calculate it. You can inject various utilities into the function as parameters.
Setting a custom no search results message#
When you're using a searchable select or multi-select, you may want to display a custom message when no search results are found. You can do this using the noOptionsSearchResultsMessage() method:
use Filament\Tables\Columns\SelectColumn;
SelectColumn::make('author_id')
->optionsRelationship(name: 'author', titleAttribute: 'name')
->searchableOptions()
->noOptionsSearchResultsMessage('No authors found.')
noOptionsSearchResultsMessage() method also accepts a function to dynamically calculate it. You can inject various utilities into the function as parameters.
Setting a custom search prompt#
When you're using a searchable select or multi-select, you may want to display a custom message when the user has not yet entered a search term. You can do this using the optionsSearchPrompt() method:
use Filament\Tables\Columns\SelectColumn;
SelectColumn::make('author_id')
->optionsRelationship(name: 'author', titleAttribute: 'name')
->searchableOptions(['name', 'email'])
->optionsSearchPrompt('Search authors by their name or email address')
optionsSearchPrompt() method also accepts a function to dynamically calculate it. You can inject various utilities into the function as parameters.
Setting a custom searching message#
When you're using a searchable select or multi-select, you may want to display a custom message while the search results are being loaded. You can do this using the optionsSearchingMessage() method:
use Filament\Tables\Columns\SelectColumn;
SelectColumn::make('author_id')
->optionsRelationship(name: 'author', titleAttribute: 'name')
->searchableOptions()
->optionsSearchingMessage('Searching authors...')
optionsSearchingMessage() method also accepts a function to dynamically calculate it. You can inject various utilities into the function as parameters.
Tweaking the search debounce#
By default, Filament will wait 1000 milliseconds (1 second) before searching for options when the user types in a searchable select or multi-select. It will also wait 1000 milliseconds between searches, if the user is continuously typing into the search input. You can change this using the optionsSearchDebounce() method:
use Filament\Tables\Columns\SelectColumn;
SelectColumn::make('author_id')
->optionsRelationship(name: 'author', titleAttribute: 'name')
->searchableOptions()
->optionsSearchDebounce(500)
Ensure that you are not lowering the debounce too much, as this may cause the select to become slow and unresponsive due to a high number of network requests to retrieve options from server.
optionsSearchDebounce() method also accepts a function to dynamically calculate it. You can inject various utilities into the function as parameters.
Integrating with an Eloquent relationship#
You may employ the optionsRelationship() method of the SelectColumn to configure a BelongsTo relationship to automatically retrieve options from. The titleAttribute is the name of a column that will be used to generate a label for each option:
use Filament\Tables\Columns\SelectColumn;
SelectColumn::make('author_id')
->optionsRelationship(name: 'author', titleAttribute: 'name')
Searching relationship options across multiple columns#
By default, if the select is also searchable, Filament will return search results for the relationship based on the title column of the relationship. If you'd like to search across multiple columns, you can pass an array of columns to the searchableOptions() method:
use Filament\Tables\Columns\SelectColumn;
SelectColumn::make('author_id')
->optionsRelationship(name: 'author', titleAttribute: 'name')
->searchableOptions(['name', 'email'])
Preloading relationship options#
If you'd like to populate the searchable options from the database when the page is loaded, instead of when the user searches, you can use the preloadOptions() method:
use Filament\Tables\Columns\SelectColumn;
SelectColumn::make('author_id')
->optionsRelationship(name: 'author', titleAttribute: 'name')
->searchableOptions()
->preloadOptions()
Optionally, you may pass a boolean value to control if the input should be preloaded or not:
use Filament\Tables\Columns\SelectColumn;
SelectColumn::make('author_id')
->optionsRelationship(name: 'author', titleAttribute: 'name')
->searchableOptions()
->preloadOptions(FeatureFlag::active())
preloadOptions() method also accepts a function to dynamically calculate it. You can inject various utilities into the function as parameters.
Excluding the current record#
When working with recursive relationships, you will likely want to remove the current record from the set of results.
This can be easily be done using the ignoreRecord argument:
use Filament\Tables\Columns\SelectColumn;
SelectColumn::make('parent_id')
->optionsRelationship(name: 'parent', titleAttribute: 'name', ignoreRecord: true)
Customizing the relationship query#
You may customize the database query that retrieves options using the third parameter of the optionsRelationship() method:
use Filament\Tables\Columns\SelectColumn;
use Illuminate\Database\Eloquent\Builder;
SelectColumn::make('author_id')
->optionsRelationship(
name: 'author',
titleAttribute: 'name',
modifyQueryUsing: fn (Builder $query) => $query->withTrashed(),
)
modifyQueryUsing argument can inject various utilities into the function as parameters.
Customizing the relationship option labels#
If you'd like to customize the label of each option, maybe to be more descriptive, or to concatenate a first and last name, you could use a virtual column in your database migration:
$table->string('full_name')->virtualAs('concat(first_name, \' \', last_name)');
use Filament\Tables\Columns\SelectColumn;
SelectColumn::make('author_id')
->optionsRelationship(name: 'author', titleAttribute: 'full_name')
Alternatively, you can use the getOptionLabelFromRecordUsing() method to transform an option's Eloquent model into a label:
use Filament\Tables\Columns\SelectColumn;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
SelectColumn::make('author_id')
->optionsRelationship(
name: 'author',
modifyQueryUsing: fn (Builder $query) => $query->orderBy('first_name')->orderBy('last_name'),
)
->getOptionLabelFromRecordUsing(fn (Model $record) => "{$record->first_name} {$record->last_name}")
->searchableOptions(['first_name', 'last_name'])
getOptionLabelFromRecordUsing() method can inject various utilities into the function as parameters.
Remembering options#
By default, when using optionsRelationship(), Filament will remember the options for the duration of the table page to improve performance. This means that the options function will only run once per table page instead of once per cell. You can disable this behavior using the rememberOptions(false) method:
use Filament\Tables\Columns\SelectColumn;
SelectColumn::make('author_id')
->optionsRelationship(name: 'author', titleAttribute: 'name')
->rememberOptions(false)
rememberOptions() method also accepts a function to dynamically calculate it. You can inject various utilities into the function as parameters.
Allowing HTML in the option labels#
By default, Filament will escape any HTML in the option labels. If you'd like to allow HTML, you can use the allowOptionsHtml() method:
use Filament\Tables\Columns\SelectColumn;
SelectColumn::make('technology')
->options([
'tailwind' => '<span class="text-blue-500">Tailwind</span>',
'alpine' => '<span class="text-green-500">Alpine</span>',
'laravel' => '<span class="text-red-500">Laravel</span>',
'livewire' => '<span class="text-pink-500">Livewire</span>',
])
->searchableOptions()
->allowOptionsHtml()
Optionally, you may pass a boolean value to control if the input should allow HTML or not:
use Filament\Tables\Columns\SelectColumn;
SelectColumn::make('technology')
->options([
'tailwind' => '<span class="text-blue-500">Tailwind</span>',
'alpine' => '<span class="text-green-500">Alpine</span>',
'laravel' => '<span class="text-red-500">Laravel</span>',
'livewire' => '<span class="text-pink-500">Livewire</span>',
])
->searchableOptions()
->allowOptionsHtml(FeatureFlag::active())
allowOptionsHtml() method also accepts a function to dynamically calculate it. You can inject various utilities into the function as parameters.
Wrap or truncate option labels#
When using the JavaScript select, labels that exceed the width of the select element will wrap onto multiple lines by default. Alternatively, you may choose to truncate overflowing labels.
use Filament\Tables\Columns\SelectColumn;
SelectColumn::make('truncate')
->wrapOptionLabels(false)
wrapOptionLabels() method also accepts a function to dynamically calculate it. You can inject various utilities into the function as parameters.
Disable placeholder selection#
You can prevent the placeholder (null option) from being selected using the selectablePlaceholder(false) method:
use Filament\Tables\Columns\SelectColumn;
SelectColumn::make('status')
->options([
'draft' => 'Draft',
'reviewing' => 'Reviewing',
'published' => 'Published',
])
->selectablePlaceholder(false)
selectablePlaceholder() method also accepts a function to dynamically calculate it. You can inject various utilities into the function as parameters.
Disabling specific options#
You can disable specific options using the disableOptionWhen() method. It accepts a closure, in which you can check if the option with a specific $value should be disabled:
use Filament\Tables\Columns\SelectColumn;
SelectColumn::make('status')
->options([
'draft' => 'Draft',
'reviewing' => 'Reviewing',
'published' => 'Published',
])
->default('draft')
->disableOptionWhen(fn (string $value): bool => $value === 'published')
Limiting the number of options#
You can limit the number of options that are displayed in a searchable select or multi-select using the optionsLimit() method. The default is 50:
use Filament\Tables\Columns\SelectColumn;
SelectColumn::make('author_id')
->optionsRelationship(name: 'author', titleAttribute: 'name')
->searchableOptions()
->optionsLimit(20)
Ensure that you are not raising the limit too high, as this may cause the select to become slow and unresponsive due to high in-browser memory usage.
optionsLimit() method also accepts a function to dynamically calculate it. You can inject various utilities into the function as parameters.
Validation#
You can validate the input by passing any Laravel validation rules in an array:
use Filament\Tables\Columns\SelectColumn;
SelectColumn::make('status')
->options([
'draft' => 'Draft',
'reviewing' => 'Reviewing',
'published' => 'Published',
])
->rules(['required'])
Valid options validation (in rule)#
The in rule ensures that users cannot select an option that is not in the list of options. This is an important rule for data integrity purposes, so Filament applies it by default to all select fields.
Since there are many ways for a select field to populate its options, and in many cases the options are not all loaded into the select by default and require searching to retrieve them, Filament uses the presence of a valid "option label" to determine whether the selected value exists. It also checks if that option is disabled or not.
If you are using a custom search query to retrieve options, you should ensure that the getOptionLabelUsing() method is defined, so that Filament can validate the selected value against the available options:
use Filament\Tables\Columns\SelectColumn;
SelectColumn::make('author_id')
->searchableOptions()
->getOptionsSearchResultsUsing(fn (string $search): array => Author::query()
->where('name', 'like', "%{$search}%")
->limit(50)
->pluck('name', 'id')
->all())
->getOptionLabelUsing(fn (string $value): ?string => Author::find($value)?->name),
The getOptionLabelUsing() method should return null if the option is not valid, to allow Filament to determine that the selected value is not in the list of options. If the option is valid, it should return the label of the option.
If you are using the optionsRelationship() method, the getOptionLabelUsing() method will be automatically defined for you, so you don't need to worry about it.
Lifecycle hooks#
Hooks may be used to execute code at various points within the select's lifecycle:
SelectColumn::make()
->beforeStateUpdated(function ($record, $state) {
// Runs before the state is saved to the database.
})
->afterStateUpdated(function ($record, $state) {
// Runs after the state is saved to the database.
})
Security#
Authorization#
The select column does not automatically check Laravel Model Policies before saving changes. When a user updates a value via the select column, Filament checks whether the column is disabled() but does not run any update policy gate check. This means that if a user can see a record in the table and the column is not disabled, they can update that column's value regardless of any update policy you have defined. If you need to restrict who can edit this column, you should use the disabled() method to conditionally prevent editing based on your own authorization logic, for example disabled(fn ($record) => $record->user_id !== auth()->id()). Alternatively, consider using a full edit page or modal action where Filament's resource authorization is enforced.