andrewdwallo/filament-selectify
Filament Selectify is a Laravel/Filament package that upgrades standard select fields into a more flexible, searchable dropdown experience, helping you build cleaner forms and admin panels with less custom code. It integrates smoothly with Filament resources and forms.
andrewdwallo/filament-selectify adds two form fields — ToggleButtons and RadioButtons — that behave like a Select/Radio but render as clickable button groups. It is a UI-layer package: no migrations, no config file, no service provider wiring beyond Filament's auto-discovery.
Install
composer require andrewdwallo/filament-selectify
Version matrix — check this before anything else. v3.0.0 is the Filament v4 compatibility release, and it is a new major, so the constraint you resolve depends entirely on your Filament major:
composer show andrewdwallo/filament-selectify
composer show filament/filament
andrewdwallo/filament-selectify:^3.0^2.0 (composer will pick this automatically if you don't override)^1.x — confirm in the package's composer.json before pinningThe dependabot PRs in the v3.0.0 notes (fetch-metadata 2.2.0 → 2.4.0) are CI-only and have no runtime impact. The one substantive change is the Filament v4 port.
Where to look first
vendor/andrewdwallo/filament-selectify/README.md — the canonical examples.vendor/andrewdwallo/filament-selectify/composer.json — the filament/filament constraint is the fastest way to confirm which major you actually installed.vendor/andrewdwallo/filament-selectify/src/Components/ — the actual field classes and every chainable modifier available in your installed version. After a major bump, verify the use statement from here rather than trusting older snippets.vendor/andrewdwallo/filament-selectify/resources/views/ — useful when you need to understand markup, Tailwind classes, or override styling.First use case: replace a status Select in a resource form
use AndrewdWall\FilamentSelectify\Components\ToggleButtons;
ToggleButtons::make('status')
->label('Status')
->options([
'draft' => 'Draft',
'review' => 'In review',
'published' => 'Published',
])
->colors([
'draft' => 'gray',
'review' => 'warning',
'published' => 'success',
])
->icons([
'draft' => 'heroicon-o-pencil',
'review' => 'heroicon-o-eye',
'published' => 'heroicon-o-check-circle',
])
->default('draft')
->inline()
->required();
That is the 80% use case: an enum-backed status or a small set of mutually exclusive options where a dropdown hides the choices and a native radio list looks flat. Drop it into any Schema (resource form, action modal, wizard step) exactly where the Select was.
Enum-backed options. If your version accepts an enum class directly, use ->options(Status::class). If not, map explicitly so keys and labels stay predictable:
->options(
collect(Status::cases())
->mapWithKeys(fn (Status $s) => [$s->value => $s->label()])
->all()
)
->colors(
collect(Status::cases())
->mapWithKeys(fn (Status $s) => [$s->value => $s->color()])
->all()
)
Keep colors() and options() keyed identically; a mismatched key silently falls back to the default color rather than erroring.
Two-state booleans. ToggleButtons is a good fit for is_active, is_featured, visibility when a checkbox feels too small and a toggle switch implies immediate persistence. Store the same scalar you already store (1/0 or 'yes'/'no') so casts and policies don't change:
ToggleButtons::make('is_active')
->options([1 => 'Active', 0 => 'Inactive'])
->colors([1 => 'success', 0 => 'danger'])
->default(1)
->inline();
Reactive forms. These fields are normal Filament fields, so live() and afterStateUpdated() work as usual. On Filament v4 the closures still receive Set/Get, but the surrounding page class may be a Schema-based resource — the field-level API is unchanged:
ToggleButtons::make('type')
->options(['personal' => 'Personal', 'business' => 'Business'])
->live()
->afterStateUpdated(fn (Set $set) => $set('company_name', null)),
TextInput::make('company_name')
->visible(fn (Get $get) => $get('type') === 'business'),
Grouped / radio-style choices. RadioButtons is the better semantic choice when the options are not binary — plans, frequencies, delivery methods — especially in settings pages and action modals where a Select dropdown would be awkward. Pair with ->inline() for short labels and let it wrap on mobile; use the field's column/grid modifier (if exposed in your version) for longer labels.
Composition. Because these are standard Field subclasses, they compose with ->columnSpanFull(), ->hidden(), ->disabled(), ->helperText(), ->hint(), Repeater state paths, Wizard steps, and RelationManager forms. No special handling is required. In Filament v4, layout components live under Filament\Schemas\Components rather than Filament\Forms\Components — if you're porting a form, that's a use change in your code, not in the package.
Testing. They hydrate and dehydrate like any other field, so Livewire form tests are unchanged:
livewire(CreatePost::class)
->fillForm(['status' => 'published'])
->call('create')
->assertHasNoFormErrors();
$this->assertDatabaseHas('posts', ['status' => 'published']);
Watch the import. Filament core also ships a ToggleButtons field. Importing the wrong one is the most common confusion, and a Filament v3→v4 upgrade is exactly when autocomplete starts offering you the wrong one:
use AndrewdWall\FilamentSelectify\Components\ToggleButtons;
// not Filament\Forms\Components\ToggleButtons
Alias it if a file needs both (use ... as SelectifyToggleButtons;). After bumping to v3.0.0, grep the src/Components/ directory once to confirm the public namespace before updating every form.
v3.0.0 requires Filament v4 — the whole panel moves with it. This is the real upgrade risk: it's not a leaf package you can float independently. Before bumping, confirm every other Filament plugin, custom page, and theme in the project has a v4-compatible release, then upgrade Filament and Selectify in the same composer require so composer can't resolve you into a half-upgraded state:
composer require filament/filament:^4.0 andrewdwallo/filament-selectify:^3.0 -W
If you're not ready for v4, pin explicitly — ^2.0 for Filament v3 — or a later composer update can try to drag you forward.
State keys are strings. PHP casts numeric array keys, and Livewire round-trips form state as JSON. A 0/1 options array can hydrate as "0"/"1" depending on your model casts. If ->default(1) doesn't visually select, try ->default('1') or align the cast on the model. This bites hardest with boolean columns.
Nothing is unselected by default. Radio-style fields have no built-in "clear" affordance. For nullable columns, either add an explicit '' => 'None' option or use ->nullable() plus a separate clear action. Don't assume clicking the active button toggles it off.
Validation is still yours. The UI constrains choices, but state is client-supplied. Keep ->required() and, for enum-backed columns, an ->in(...) rule or enum cast on the model. required() alone won't reject a tampered value.
Colors must be Filament color names. primary, success, warning, danger, info, gray — not hex codes. If a custom panel color is registered, use its registered name. Unknown keys fall back silently, which makes "why is this button gray?" a five-minute debugging session. Filament v4's colour token handling is stricter in some places; if a colour that worked on v3 renders oddly after the bump, check it against the panel's registered palette first.
Custom Filament themes need the vendor views scanned — and the mechanism changed in v4. If the package's Tailwind classes get purged, the buttons render as unstyled text or lose active-state colours, usually only in production builds.
On Filament v3 (tailwind.config.js):
content: [
'./vendor/andrewdwallo/filament-selectify/resources/views/**/*.blade.php',
],
On Filament v4 (Tailwind CSS v4, CSS-first config), add a @source directive to your theme CSS instead:
@source '../../../../vendor/andrewdwallo/filament-selectify/resources/views/**/*.blade.php';
Then npm run build. Re-run php artisan filament:theme docs check on v4 — the generated theme file layout differs from v3, and old tailwind.config.js content globs are simply ignored.
After upgrades, rebuild assets. php artisan filament:assets (plus view:clear and optimize:clear) resolves most "it worked yesterday" styling issues — and is mandatory after a Filament major bump. If the package publishes views, republish deliberately and diff — do not blindly overwrite customizations, especially when crossing a major that may have changed the markup.
Accessibility and mobile. Icon-only buttons need labels or tooltips; screen readers get nothing from a heroicon alone. Long option sets wrap poorly — prefer RadioButtons with a grid layout, or fall back to a Select beyond roughly six choices.
Debugging. Add ->live() and dd($state) in afterStateUpdated() to confirm the value type. Inspect the rendered DOM for the active-state class; if it's present but invisible, it's a CSS/purge issue, not a state issue. If the field renders at all but behaves like a plain HTML input, you are almost certainly importing Filament's core ToggleButtons instead of the package's.
Extension points. Subclass the component to bake in your team's color/icon conventions, or use ->extraAttributes([...]) for one-off hooks. Publishing and overriding the Blade views is viable for structural changes, but prefer wrapping the field in a small factory function (e.g. StatusToggle::make()) so view overrides stay in one place — and so a future major (like this one) has exactly one place to fix. Given the package's size and its modest star footprint, expect to read the source rather than find extensive docs; the 40-file PR that landed v4 support is a good reminder that the components are small enough that reading them is faster than searching.
How can I help you explore Laravel packages today?