[폼.필드] Select
개요
select 컴포넌트는 미리 정의된 옵션 목록에서 선택할 수 있도록 해줍니다:
use Filament\Forms\Components\Select;
Select::make('status')
->options([
'draft' => 'Draft',
'reviewing' => 'Reviewing',
'published' => 'Published',
])
JavaScript select 활성화하기
기본적으로 Filament는 네이티브 HTML5 select를 사용합니다. native(false) 메서드를 사용하여 더 커스터마이즈 가능한 JavaScript select를 활성화할 수 있습니다:
use Filament\Forms\Components\Select;
Select::make('status')
->options([
'draft' => 'Draft',
'reviewing' => 'Reviewing',
'published' => 'Published',
])
->native(false)
옵션 검색 활성화하기
searchable() 메서드를 사용하여 많은 옵션에 더 쉽게 접근할 수 있도록 검색 입력을 활성화할 수 있습니다:
use Filament\Forms\Components\Select;
Select::make('author_id')
->label('Author')
->options(User::all()->pluck('name', 'id'))
->searchable()
커스텀 검색 결과 반환하기
옵션이 많고 데이터베이스 검색이나 외부 데이터 소스를 기반으로 옵션을 채우고 싶다면, options() 대신 getSearchResultsUsing() 및 getOptionLabelUsing() 메서드를 사용할 수 있습니다.
getSearchResultsUsing() 메서드는 $key => $value 형식의 검색 결과를 반환하는 콜백을 받습니다. 현재 사용자의 검색어는 $search로 제공되며, 이를 사용해 결과를 필터링해야 합니다.
getOptionLabelUsing() 메서드는 선택된 옵션 $value를 라벨로 변환하는 콜백을 받습니다. 이 메서드는 폼이 처음 로드될 때, 사용자가 아직 검색을 하지 않은 경우에 사용됩니다. 그렇지 않으면 현재 선택된 옵션을 표시할 라벨이 제공되지 않습니다.
커스텀 검색 결과를 제공하려면 getSearchResultsUsing()과 getOptionLabelUsing()을 모두 select에 사용해야 합니다:
Select::make('author_id')
->searchable()
->getSearchResultsUsing(fn (string $search): array => User::where('name', 'like', "%{$search}%")->limit(50)->pluck('name', 'id')->toArray())
->getOptionLabelUsing(fn ($value): ?string => User::find($value)?->name),다중 선택
Select 컴포넌트의 multiple() 메서드를 사용하면 옵션 목록에서 여러 값을 선택할 수 있습니다:
use Filament\Forms\Components\Select;
Select::make('technologies')
->multiple()
->options([
'tailwind' => 'Tailwind CSS',
'alpine' => 'Alpine.js',
'laravel' => 'Laravel',
'livewire' => 'Laravel Livewire',
])
이 옵션들은 JSON 형식으로 반환됩니다. Eloquent를 사용해 저장할 경우, 모델 속성에 array 캐스팅을 추가해야 합니다:
use Illuminate\Database\Eloquent\Model;
class App extends Model
{
protected $casts = [
'technologies' => 'array',
];
// ...
}커스텀 검색 결과를 반환하는 경우, getOptionLabelUsing() 대신 getOptionLabelsUsing()을 정의해야 합니다. 콜백에는 $value 대신 $values가 전달되며, 라벨과 해당 값의 $key => $value 배열을 반환해야 합니다:
Select::make('technologies')
->multiple()
->searchable()
->getSearchResultsUsing(fn (string $search): array => Technology::where('name', 'like', "%{$search}%")->limit(50)->pluck('name', 'id')->toArray())
->getOptionLabelsUsing(fn (array $values): array => Technology::whereIn('id', $values)->pluck('name', 'id')->toArray()),옵션 그룹화하기
옵션을 라벨 아래에 그룹화하여 더 잘 정리할 수 있습니다. 이를 위해 options() 또는 일반적으로 옵션 배열을 전달하는 곳에 그룹 배열을 전달할 수 있습니다. 배열의 키는 그룹 라벨로 사용되고, 값은 해당 그룹의 옵션 배열입니다:
use Filament\Forms\Components\Select;
Select::make('status')
->searchable()
->options([
'In Process' => [
'draft' => 'Draft',
'reviewing' => 'Reviewing',
],
'Reviewed' => [
'published' => 'Published',
'rejected' => 'Rejected',
],
])
Eloquent 관계와 통합하기
Livewire 컴포넌트 내에서 폼을 빌드하는 경우, 반드시 폼의 모델을 설정해야 합니다. 그렇지 않으면 Filament는 관계를 가져올 모델을 알 수 없습니다.
Select의 relationship() 메서드를 사용하여 BelongsTo 관계를 자동으로 옵션으로 가져오도록 설정할 수 있습니다. titleAttribute는 각 옵션의 라벨을 생성하는 데 사용되는 컬럼명입니다:
use Filament\Forms\Components\Select;
Select::make('author_id')
->relationship(name: 'author', titleAttribute: 'name')multiple() 메서드는 relationship()과 함께 사용하여 BelongsToMany 관계를 사용할 수 있습니다. Filament는 관계에서 옵션을 불러오고, 폼 제출 시 관계의 pivot 테이블에 다시 저장합니다. name이 제공되지 않으면, Filament는 필드명을 관계명으로 사용합니다:
use Filament\Forms\Components\Select;
Select::make('technologies')
->multiple()
->relationship(titleAttribute: 'name')multiple()과 relationship()을 사용할 때 disabled()를 함께 사용한다면, 반드시 disabled()를 relationship()보다 먼저 호출해야 합니다. 이렇게 하면 relationship() 내부의 dehydrated() 호출이 disabled()의 호출에 의해 덮어써지지 않습니다:
use Filament\Forms\Components\Select;
Select::make('technologies')
->multiple()
->disabled()
->relationship(titleAttribute: 'name')여러 컬럼에서 관계 옵션 검색하기
기본적으로 select가 검색 가능할 때, Filament는 관계의 title 컬럼을 기준으로 검색 결과를 반환합니다. 여러 컬럼에서 검색하고 싶다면, searchable() 메서드에 컬럼 배열을 전달할 수 있습니다:
use Filament\Forms\Components\Select;
Select::make('author_id')
->relationship(name: 'author', titleAttribute: 'name')
->searchable(['name', 'email'])관계 옵션 미리 불러오기
페이지가 로드될 때 데이터베이스에서 검색 가능한 옵션을 미리 불러오고 싶다면, preload() 메서드를 사용할 수 있습니다:
use Filament\Forms\Components\Select;
Select::make('author_id')
->relationship(name: 'author', titleAttribute: 'name')
->searchable()
->preload()현재 레코드 제외하기
재귀 관계를 다룰 때는 현재 레코드를 결과 집합에서 제거하고 싶을 수 있습니다.
이것은 ignoreRecord 인자를 사용하여 쉽게 할 수 있습니다:
use Filament\Forms\Components\Select;
Select::make('parent_id')
->relationship(name: 'parent', titleAttribute: 'name', ignoreRecord: true)관계 쿼리 커스터마이즈하기
옵션을 가져오는 데이터베이스 쿼리를 relationship() 메서드의 세 번째 파라미터로 커스터마이즈할 수 있습니다:
use Filament\Forms\Components\Select;
use Illuminate\Database\Eloquent\Builder;
Select::make('author_id')
->relationship(
name: 'author',
titleAttribute: 'name',
modifyQueryUsing: fn (Builder $query) => $query->withTrashed(),
)modifyQueryUsing 함수에서 현재 검색 쿼리에 접근하고 싶다면, $search를 주입할 수 있습니다.
관계 옵션 라벨 커스터마이즈하기
각 옵션의 라벨을 더 설명적으로 만들거나, 이름과 성을 합치고 싶다면, 데이터베이스 마이그레이션에서 가상 컬럼을 사용할 수 있습니다:
$table->string('full_name')->virtualAs('concat(first_name, \' \', last_name)');use Filament\Forms\Components\Select;
Select::make('author_id')
->relationship(name: 'author', titleAttribute: 'full_name')또는, getOptionLabelFromRecordUsing() 메서드를 사용하여 옵션의 Eloquent 모델을 라벨로 변환할 수 있습니다:
use Filament\Forms\Components\Select;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
Select::make('author_id')
->relationship(
name: 'author',
modifyQueryUsing: fn (Builder $query) => $query->orderBy('first_name')->orderBy('last_name'),
)
->getOptionLabelFromRecordUsing(fn (Model $record) => "{$record->first_name} {$record->last_name}")
->searchable(['first_name', 'last_name'])관계에 피벗 데이터 저장하기
multiple() 관계를 사용하고 피벗 테이블에 추가 컬럼이 있다면, pivotData() 메서드를 사용하여 저장할 데이터를 지정할 수 있습니다:
use Filament\Forms\Components\Select;
Select::make('primaryTechnologies')
->relationship(name: 'technologies', titleAttribute: 'name')
->multiple()
->pivotData([
'is_primary' => true,
])모달에서 새 옵션 생성하기
커스텀 폼을 정의하여 새 레코드를 생성하고 BelongsTo 관계에 연결할 수 있습니다:
use Filament\Forms\Components\Select;
Select::make('author_id')
->relationship(name: 'author', titleAttribute: 'name')
->createOptionForm([
Forms\Components\TextInput::make('name')
->required(),
Forms\Components\TextInput::make('email')
->required()
->email(),
]),
폼은 모달에서 열리며, 사용자가 데이터를 입력할 수 있습니다. 폼 제출 시 새 레코드가 필드에 선택됩니다.

새 옵션 생성 커스터마이즈하기
폼에서 정의한 새 옵션의 생성 과정을 createOptionUsing() 메서드를 사용해 커스터마이즈할 수 있습니다. 이 메서드는 새로 생성된 레코드의 기본 키를 반환해야 합니다:
use Filament\Forms\Components\Select;
Select::make('author_id')
->relationship(name: 'author', titleAttribute: 'name')
->createOptionForm([
// ...
])
->createOptionUsing(function (array $data): int {
return auth()->user()->team->members()->create($data)->getKey();
}),모달에서 선택된 옵션 편집하기
커스텀 폼을 정의하여 선택된 레코드를 편집하고 BelongsTo 관계에 다시 저장할 수 있습니다:
use Filament\Forms\Components\Select;
Select::make('author_id')
->relationship(name: 'author', titleAttribute: 'name')
->editOptionForm([
Forms\Components\TextInput::make('name')
->required(),
Forms\Components\TextInput::make('email')
->required()
->email(),
]),
폼은 모달에서 열리며, 사용자가 데이터를 입력할 수 있습니다. 폼 제출 시 폼의 데이터가 레코드에 다시 저장됩니다.

MorphTo 관계 다루기
MorphTo 관계는 특별합니다. 다양한 모델에서 레코드를 선택할 수 있기 때문입니다. 그래서 실제로 select 필드가 아니라 필드셋 안에 2개의 select 필드가 있는 전용 MorphToSelect 컴포넌트가 있습니다. 첫 번째 select 필드는 타입을 선택하고, 두 번째는 해당 타입의 레코드를 선택합니다.
MorphToSelect를 사용하려면, 각 타입에 대한 옵션 렌더링 방법을 알려주는 types()를 컴포넌트에 전달해야 합니다:
use Filament\Forms\Components\MorphToSelect;
MorphToSelect::make('commentable')
->types([
MorphToSelect\Type::make(Product::class)
->titleAttribute('name'),
MorphToSelect\Type::make(Post::class)
->titleAttribute('title'),
])각 morph 타입의 옵션 라벨 커스터마이즈하기
titleAttribute()는 각 product나 post에서 타이틀을 추출하는 데 사용됩니다. 각 옵션의 라벨을 커스터마이즈하고 싶다면, getOptionLabelFromRecordUsing() 메서드를 사용해 Eloquent 모델을 라벨로 변환할 수 있습니다:
use Filament\Forms\Components\MorphToSelect;
MorphToSelect::make('commentable')
->types([
MorphToSelect\Type::make(Product::class)
->getOptionLabelFromRecordUsing(fn (Product $record): string => "{$record->name} - {$record->slug}"),
MorphToSelect\Type::make(Post::class)
->titleAttribute('title'),
])각 morph 타입의 관계 쿼리 커스터마이즈하기
옵션을 가져오는 데이터베이스 쿼리를 modifyOptionsQueryUsing() 메서드로 커스터마이즈할 수 있습니다:
use Filament\Forms\Components\MorphToSelect;
use Illuminate\Database\Eloquent\Builder;
MorphToSelect::make('commentable')
->types([
MorphToSelect\Type::make(Product::class)
->titleAttribute('name')
->modifyOptionsQueryUsing(fn (Builder $query) => $query->whereBelongsTo($this->team)),
MorphToSelect\Type::make(Post::class)
->titleAttribute('title')
->modifyOptionsQueryUsing(fn (Builder $query) => $query->whereBelongsTo($this->team)),
])select 필드의 많은 옵션들이
MorphToSelect에서도 사용 가능합니다. 예:searchable(),preload(),native(),allowHtml(),optionsLimit()등.
옵션 라벨에 HTML 허용하기
기본적으로 Filament는 옵션 라벨의 모든 HTML을 이스케이프합니다. HTML을 허용하고 싶다면, allowHtml() 메서드를 사용할 수 있습니다:
use Filament\Forms\Components\Select;
Select::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>',
])
->searchable()
->allowHtml()HTML이 안전하게 렌더링될 수 있도록 반드시 확인해야 합니다. 그렇지 않으면 애플리케이션이 XSS 공격에 취약해질 수 있습니다.
플레이스홀더 선택 비활성화하기
selectablePlaceholder() 메서드를 사용하여 플레이스홀더(null 옵션)가 선택되는 것을 방지할 수 있습니다:
use Filament\Forms\Components\Select;
Select::make('status')
->options([
'draft' => 'Draft',
'reviewing' => 'Reviewing',
'published' => 'Published',
])
->default('draft')
->selectablePlaceholder(false)특정 옵션 비활성화하기
disableOptionWhen() 메서드를 사용하여 특정 옵션을 비활성화할 수 있습니다. 이 메서드는 클로저를 받으며, 특정 $value의 옵션을 비활성화할지 확인할 수 있습니다:
use Filament\Forms\Components\Select;
Select::make('status')
->options([
'draft' => 'Draft',
'reviewing' => 'Reviewing',
'published' => 'Published',
])
->default('draft')
->disableOptionWhen(fn (string $value): bool => $value === 'published')비활성화되지 않은 옵션을 가져오고 싶다면(예: 유효성 검사 목적), getEnabledOptions()을 사용할 수 있습니다:
use Filament\Forms\Components\Select;
Select::make('status')
->options([
'draft' => 'Draft',
'reviewing' => 'Reviewing',
'published' => 'Published',
])
->default('draft')
->disableOptionWhen(fn (string $value): bool => $value === 'published')
->in(fn (Select $component): array => array_keys($component->getEnabledOptions()))필드 옆에 접두/접미 텍스트 추가하기
prefix()와 suffix() 메서드를 사용하여 입력 앞뒤에 텍스트를 배치할 수 있습니다:
use Filament\Forms\Components\Select;
Select::make('domain')
->prefix('https://')
->suffix('.com')
아이콘을 접두/접미로 사용하기
prefixIcon()과 suffixIcon() 메서드를 사용하여 입력 앞뒤에 아이콘을 배치할 수 있습니다:
use Filament\Forms\Components\Select;
Select::make('domain')
->suffixIcon('heroicon-m-globe-alt')접두/접미 아이콘 색상 설정하기
접두/접미 아이콘은 기본적으로 회색이지만, prefixIconColor()와 suffixIconColor() 메서드를 사용해 다른 색상으로 설정할 수 있습니다:
use Filament\Forms\Components\Select;
Select::make('domain')
->suffixIcon('heroicon-m-check-circle')
->suffixIconColor('success')커스텀 로딩 메시지 설정하기
검색 가능한 select 또는 multi-select를 사용할 때, 옵션이 로딩되는 동안 커스텀 메시지를 표시하고 싶을 수 있습니다. loadingMessage() 메서드를 사용해 설정할 수 있습니다:
use Filament\Forms\Components\Select;
Select::make('author_id')
->relationship(name: 'author', titleAttribute: 'name')
->searchable()
->loadingMessage('Loading authors...')커스텀 검색 결과 없음 메시지 설정하기
검색 가능한 select 또는 multi-select를 사용할 때, 검색 결과가 없을 때 커스텀 메시지를 표시하고 싶을 수 있습니다. noSearchResultsMessage() 메서드를 사용해 설정할 수 있습니다:
use Filament\Forms\Components\Select;
Select::make('author_id')
->relationship(name: 'author', titleAttribute: 'name')
->searchable()
->noSearchResultsMessage('No authors found.')커스텀 검색 프롬프트 설정하기
검색 가능한 select 또는 multi-select를 사용할 때, 사용자가 아직 검색어를 입력하지 않았을 때 커스텀 메시지를 표시하고 싶을 수 있습니다. searchPrompt() 메서드를 사용해 설정할 수 있습니다:
use Filament\Forms\Components\Select;
Select::make('author_id')
->relationship(name: 'author', titleAttribute: 'name')
->searchable(['name', 'email'])
->searchPrompt('Search authors by their name or email address')커스텀 검색 중 메시지 설정하기
검색 가능한 select 또는 multi-select를 사용할 때, 검색 결과가 로딩되는 동안 커스텀 메시지를 표시하고 싶을 수 있습니다. searchingMessage() 메서드를 사용해 설정할 수 있습니다:
use Filament\Forms\Components\Select;
Select::make('author_id')
->relationship(name: 'author', titleAttribute: 'name')
->searchable()
->searchingMessage('Searching authors...')검색 디바운스 조정하기
기본적으로 Filament는 사용자가 검색 가능한 select 또는 multi-select에 입력할 때 옵션을 검색하기 전 1000밀리초(1초) 동안 대기합니다. 사용자가 계속 입력할 경우, 검색 사이에도 1000밀리초를 대기합니다. searchDebounce() 메서드를 사용해 이 값을 변경할 수 있습니다:
use Filament\Forms\Components\Select;
Select::make('author_id')
->relationship(name: 'author', titleAttribute: 'name')
->searchable()
->searchDebounce(500)디바운스 값을 너무 낮게 설정하면, 서버에서 옵션을 가져오기 위한 네트워크 요청이 많아져 select가 느려지고 반응이 없을 수 있으니 주의하세요.
옵션 개수 제한하기
검색 가능한 select 또는 multi-select에서 표시되는 옵션의 개수를 optionsLimit() 메서드로 제한할 수 있습니다. 기본값은 50입니다:
use Filament\Forms\Components\Select;
Select::make('author_id')
->relationship(name: 'author', titleAttribute: 'name')
->searchable()
->optionsLimit(20)옵션 개수 제한을 너무 높게 설정하면, 브라우저 메모리 사용량이 많아져 select가 느려지고 반응이 없을 수 있으니 주의하세요.
Select 유효성 검사
유효성 검사 페이지에 나열된 모든 규칙 외에도, select에만 해당하는 추가 규칙이 있습니다.
선택된 항목 유효성 검사
multi-select에서 선택할 수 있는 항목의 최소 및 최대 개수를 minItems()와 maxItems() 메서드로 유효성 검사할 수 있습니다:
use Filament\Forms\Components\Select;
Select::make('technologies')
->multiple()
->options([
'tailwind' => 'Tailwind CSS',
'alpine' => 'Alpine.js',
'laravel' => 'Laravel',
'livewire' => 'Laravel Livewire',
])
->minItems(1)
->maxItems(3)select 액션 오브젝트 커스터마이즈하기
이 필드는 내부 버튼을 쉽게 커스터마이즈할 수 있도록 액션 오브젝트를 사용합니다. 액션 등록 메서드에 함수를 전달하여 이 버튼들을 커스터마이즈할 수 있습니다. 함수는 $action 오브젝트에 접근할 수 있으며, 이를 사용해 커스터마이즈하거나 모달을 커스터마이즈할 수 있습니다. 다음 메서드로 액션을 커스터마이즈할 수 있습니다:
createOptionAction()editOptionAction()manageOptionActions()(생성 및 편집 옵션 액션을 한 번에 커스터마이즈)
다음은 액션을 커스터마이즈하는 예시입니다:
use Filament\Forms\Components\Actions\Action;
use Filament\Forms\Components\Select;
Select::make('author_id')
->relationship(name: 'author', titleAttribute: 'name')
->createOptionAction(
fn (Action $action) => $action->modalWidth('3xl'),
)