Skip to main content
← Back to Table of Contents

Summary

Rich user picker extending SelectField: avatar, name, email, and verified badge in dropdown and trigger. Single selection shows a compact rich trigger; multiple selection shows a names summary in the trigger plus removable avatar tags below the field.
ClassBjanczak\FilamentFlexFields\Filament\Forms\Components\UserSelect
State typestring|int|null (single) or list<string|int> (multiple)
FieldTypeuser_select
ParentSelectField — inherits select API unless overridden below
For read-only user display in tables, use UserColumn instead.

Basic usage

With Eloquent model search (optionModel):
use Bjanczak\FilamentFlexFields\Filament\Forms\Components\UserSelect;
use App\Models\User;

UserSelect::make('assignee_id')
    ->label('Assignee')
    ->optionModel(User::class)
    ->nameColumn('name')
    ->emailColumn('email')
    ->avatarColumn('avatar_url')
    ->verificationColumn('email_verified_at')
    ->searchable()
    ->required();
With a relationship:
UserSelect::make('team_member_ids')
    ->label('Team members')
    ->relationship('members', 'name')
    ->emailColumn('email')
    ->multiple()
    ->searchable();
Static rich options (no database):
UserSelect::make('reviewer_id')
    ->options([
        1 => [
            'label' => 'Jane Doe',
            'description' => 'jane@example.com',
            'image' => '/avatars/jane.jpg',
            'verified' => true,
        ],
    ]);
Custom resolvers (aligned with UserColumn):
UserSelect::make('owner_id')
    ->optionModel(User::class)
    ->getAvatarUrlUsing(fn (User $record): ?string => $record->getFilamentAvatarUrl())
    ->getNameUsing(fn (User $record): string => $record->name)
    ->isVerifiedUsing(fn (User $record): bool => $record->hasVerifiedEmail());

Display behaviour

ModeTriggerDropdown
SingleAvatar + name + email + verified badgeRich option rows; selected user hidden from list
Multiple (1 user)Same as singleSame as single
Multiple (2+ users)Truncated comma-separated names (+N when overflow)Rich option rows; removable avatar tags rendered below the field
Options for optionModel() are loaded lazily — default suggestions and search results are fetched when the dropdown opens or when the user searches, not on initial page render.

State format

Same as SelectField: scalar ID for single mode, array of IDs for multiple(). Values must match model primary keys when using optionModel() or relationship().

Validation

Inherits SelectField / Filament Select validation (required, etc.). Option keys must exist in search results or static options().

Avatar resolution order

When resolving a user record (trigger, tags, or search results):
  1. getAvatarUrlUsing() callback, if set
  2. avatarColumn() value on the model
  3. If neither yields a URL, initials are shown on a gradient surface
Use getAvatarUrlUsing(fn ($record) => $record->getFilamentAvatarUrl()) to integrate with Filament’s user avatar convention.

Configuration API (UserSelect-specific)

resolveSelectedUsersForDisplay(array $values)

Resolves custom user data shapes for the given raw values to properly display avatars and details in the trigger badges.
UserSelect::make('author_id')
    ->resolveSelectedUsersForDisplay([
        1 => ['name' => 'John Doe', 'avatar' => '/avatars/john.jpg', 'email' => 'john@example.com']
    ]);

Inherited SelectField API

All SelectField methods apply: multiple(), searchable(), options(), variant(), size(), richOptions(), native(), placeholder(), preload() (with relationship()), etc.

Public helper methods

MethodReturnsDescription
getUserModel()string|nullModel class from optionModel()
getNameColumn()stringName attribute
getEmailColumn()string|nullEmail attribute
getAvatarColumn()string|nullAvatar attribute
getVerificationColumn()string|nullVerification attribute
getMinSearchLength()intMinimum search query length
getDefaultSuggestionsLimit()intDefault suggestion count on open
shouldRenderMultipleUserTags()booltrue when multiple()
renderUserOption(array $option, string $layout)stringHTML for list, trigger, or tag layout
recordToOptionArray(Model $record)arrayNormalized option shape
resolveOptionLabelsForValues(array $values)arrayLabels per value
searchRecords(?string $search)arrayModel search results
getUserSelectInitials(string $name)stringInitials fallback
getInitialTriggerLabel()string|nullRich trigger HTML (single)
getInitialMultipleTriggerHtml()string|nullSSR trigger HTML (multiple)
getInitialSelectedUserTagsHtml()string|nullSSR tag row HTML (multiple, 2+ users)
getInitialSelectedUserEntriesForJs()list<array>Hydration payload for client display
getInitialOptionsForJs()list<array>Empty on page load for optionModel() (lazy)
getOptionsForJs()list<array>Full options for Livewire fetches

FlexField schema config

Inherits SelectField config keys plus:
Config keyMaps to
option_model / modeloptionModel()
name_columnnameColumn()
email_columnemailColumn()
avatar_columnavatarColumn()
verification_columnverificationColumn()
max_visible_avatarsmaxVisibleAvatars() (schema only; see note above)
multiplemultiple()

CSS classes

ClassRole
fff-user-selectRoot (with SelectField classes)
fff-user-select--single / --multipleMode modifier
fff-user-select-option--listDropdown option row
fff-user-select-option--triggerSingle / one-user trigger
fff-user-select-option--tagMulti-select tag chip
fff-user-select__trigger-namesComma-separated names (multiple, 2+ users)
fff-user-select__selected-tagsTag container below field
fff-user-select__selected-tagIndividual removable tag
fff-user-select__avatarAvatar wrapper
fff-user-select__verified-badgeVerified seal icon
fff-select-field--rich-list-triggerRich trigger layout

Implementation notes

  • richOptions() and allowHtml() are enabled in setUp().
  • User option shape: label, description, image, verified (optional disabled).
  • Client-side rendering uses lean JSON (user payload) with virtual scroll for lists larger than 30 options.
  • Search uses prefix LIKE on name and email by default, with relevance ordering and request-level caching.