Components Reference
Complete API reference for custom form components shipped with Filament Flex Fields (janczakb/filament-flex-fields).
This document covers custom UI components (form fields, table columns, and layout/schema components). Standard Filament fields (TextInput, Select, etc.) are mapped via FieldType and are not described here.
Table of contents
Part I — Shared concepts
- Overview
- Documentation conventions
- Control size
- Inherited Filament field API
- Assets & playground
- Rich card option shape
- Rich select option shape
- Dual listbox option shape
Part II — Components
- FlexTextInput
- FlexTextareaField
- SelectField
- UserSelect
- UserColumn
- DualListboxField
- PriceRangeField
- CreditCardField
- PhoneField
- SignatureField
- MapPickerField
- AddressAutocompleteField
- ChoiceCards
- ChoiceCheckboxCards 22.1. ImageChoiceCards
- FlexChecklist
- FlexRadiolist
- MatrixChoiceField
- SwitchField
- CurrencyField
- CountryField
- TimezoneField
- Date & time fields
- FlexVerificationCode
- AudioField
- VoiceNoteRecorderField
- VideoField
- FlexFileUpload & FlexImageUpload
- ColorSwatchField
- FlexColorPickerField
- NumberStepper
- FlexSlider
- SegmentTabs
- SegmentControl
- TrackSlider
- TrafficSplit
- RatingField
- RatingColumn
- IconColumn
- CoverCard
- ProgressBar
- ProgressCircle
- ItemCard
- ItemCardGroup
- ItemCardStack
- Layout components — quick comparison
- Form layout patterns
- SlugField & TitleSlugField
- TranslatableFields
Part I — Shared concepts
Overview
Filament Flex Fields provides modern SaaS-inspired form controls with a unified design language:- Shared size scale (
sm,md,lg) - Shared CSS tokens (
--fff-*inresources/css/base.cssand modular bundles underresources/css/) - Filament field wrapper integration (labels, validation errors, helper text)
- Optional playground page for visual QA
Filament\Forms\Components\Field, or extend a native Filament input (TextInput, Textarea, Select) while replacing the view with a styled package template.
Documentation conventions
Each component section documents four layers of API surface:Control size
Most components accept asize() method.
config/filament-flex-fields.php under the ui key, for example:
Choice card components fall back to
choice_cards_size and choice_cards_variant when used via FlexFieldFormBuilder (add these keys to config if needed).
Inherited Filament field API
Every component in Part II inherits the standard FilamentField API. Common methods:
Validation errors are displayed below the component using the standard Filament field wrapper.
All configuration methods accept a
Closure for dynamic values and support Filament utility injection.
Livewire wire:ignore strategy (map & heavy Alpine fields)
Several interactive fields (MapPickerField, AddressAutocompleteField, SelectField, PhoneField, CountryField, and others) wrap third-party or Filament Alpine trees inside wire:ignore so Livewire does not destroy DOM that Alpine manages.
Example (
MapPickerField / AddressAutocompleteField):
$entangle for state, wire:key for remounts, x-load ES module for JS.
Assets & playground
CSS is split into bundles:JavaScript (tiered chunks)
All Alpine components are compiled together in a single esbuild build withsplitting: true. If two fields import the same module from resources/js/core/ or resources/js/support/, the code is split into a shared chunk — loaded once and cached by the browser.
Currently shared chunks (auto-generated from build)
Components without entries in the manifest (e.g.
rating-field, dual-listbox) do not share code with other components — their entire logic remains inside their thin entry (which is expected).
Modules used by only a single field (e.g. core/date-time/* used only by flex-date-time-field, nouislider used only by flex-slider) remain inside their entries until another component starts importing them.
FFART — Flex Field Asset Runtime
FFART (Flex Field Asset Runtime) is the third pillar of the asset pipeline alongside server queues and Filamentx-load:
emit-assets is batch-only: hidden data-fff-asset-batch JSON plus optional data-fff-asset-consumer markers. The runtime promotes URLs to managed <link data-fff-managed-asset> nodes and uninstalls when refCount(url) === 0 (debounced), except core.css and playground bundles.
load-stylesheet emits the full stylesheetsFor($component) + alpineChunksFor($component) URL set with a required CRG consumer id via FlexFieldAssets::resolveAssetConsumerLivewireKey() / consumerAttributesForComponent(). When Filament getLivewireKey() is null, it falls back to {livewireId}.{component} or page.{component} — never a consumer-less batch (those load then get uninstalled ~150ms later). emit-assets itself refuses to ship batches without consumer attrs (defense in depth). Schema shells that own layout CSS (ItemCardStack, ItemCardGroup) register a default key with isInheritable: false so CRG gets a stable Livewire path without doubling child field keys. Table columns enqueue in setUp() and emit the same full root set from the first rendered cell via EmitsFlexFieldTableColumnAssets. Panel queued-stylesheets remains a safety net for empty tables.
Preload & delivery (server)
Every blade template rendering a component stylesheet registers CSS and Alpine chunks in request-scoped queues (FlexFieldStylesheetQueue, FlexFieldAlpineQueue). load-stylesheet immediately emits emit-assets:
- Full page —
@push('styles')into Filament@stack('styles')in<head>. - Livewire partial — hidden
data-fff-asset-batchmarker (batch-only emit; runtime loads managed links).
queued-stylesheets flushes any remaining pending() queues at STYLES_AFTER and BODY_END. At HEAD_END, critical-stylesheet-preloads may emit teleported-menu only when FlexFieldStylesheetQueue has already registered a component that depends on it (e.g. table columns in setUp()). Form fields enqueue during body render via load-stylesheet → emit-assets instead.
HoldConfirmAction preloads its Alpine entry via @push modulepreload in hold-confirm.blade.php when the action renders — not globally in HEAD_END.
Asset injector (SPA / modals)
flex-field-asset-injector.js (registered Filament JS asset at SCRIPTS_AFTER) handles:
- href deduplication (
normalizeAssetUrl, Map indices, in-flight promise cache), - loading missing CSS and Alpine chunks from morph batches,
- modal FOUC prevention (
morph.updating/morph.updated,fff-flex-fields-assets-pending/readyclasses), - managed links (
data-fff-managed-asset) with CRG refCount uninstall, scheduleResyncFromDomrAF coalescing,- protected links (
data-fff-playground-bundle,flex-fields-core.cssonly).
UserColumn, RatingColumn, IconColumn, etc.) are lazy-loaded per column via FlexFieldStylesheetQueue::enqueueFor() in the column setUp() — not via load-stylesheet in table cell blades. The queued-stylesheets partial (render hooks at STYLES_AFTER and BODY_END) flushes pending bundles once; markStylesheetsEmitted() prevents duplicates. Playground slug pages use per-slug bundles with suppressForPlaygroundBundle() so lazy CSS is not injected twice.
Playground CSS uses base playground.css plus per-slug playground-{slug}.css bundles pushed via playground-page-stylesheets.
After changing package CSS or JS:
Rich card option shape
Used by ChoiceCards and ChoiceCheckboxCards viaoptions().
Simple option
Rich option
Rich select option shape
Used by SelectField when options use a rich array shape or whenrichOptions() / optionLayout('grid') is enabled.
Simple option
Rich option
Option groups use nested arrays:
'Backend' => ['laravel' => 'Laravel', ...].
Dual listbox option shape
Used by DualListboxField viaoptions().