Skip to main content
← Back to table of contents

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

  1. Overview
  2. Documentation conventions
  3. Control size
  4. Inherited Filament field API
  5. Assets & playground
  6. Rich card option shape
  7. Rich select option shape
  8. Dual listbox option shape

Part II — Components

  1. FlexTextInput
  2. FlexTextareaField
  3. SelectField
  4. UserSelect
  5. UserColumn
  6. DualListboxField
  7. PriceRangeField
  8. CreditCardField
  9. PhoneField
  10. SignatureField
  11. MapPickerField
  12. AddressAutocompleteField
  13. ChoiceCards
  14. ChoiceCheckboxCards 22.1. ImageChoiceCards
  15. FlexChecklist
  16. FlexRadiolist
  17. MatrixChoiceField
  18. SwitchField
  19. CurrencyField
  20. CountryField
  21. TimezoneField
  22. Date & time fields
  23. FlexVerificationCode
  24. AudioField
  25. VoiceNoteRecorderField
  26. VideoField
  27. FlexFileUpload & FlexImageUpload
  28. ColorSwatchField
  29. FlexColorPickerField
  30. NumberStepper
  31. FlexSlider
  32. SegmentTabs
  33. SegmentControl
  34. TrackSlider
  35. TrafficSplit
  36. RatingField
  37. RatingColumn
  38. IconColumn
  39. CoverCard
  40. ProgressBar
  41. ProgressCircle
  42. ItemCard
  43. ItemCardGroup
  44. ItemCardStack
  45. Layout components — quick comparison
  46. Form layout patterns
  47. SlugField & TitleSlugField
  48. 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-* in resources/css/base.css and modular bundles under resources/css/)
  • Filament field wrapper integration (labels, validation errors, helper text)
  • Optional playground page for visual QA
All custom components extend 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 a size() method.
Package defaults live in 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 Filament Field 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):
When adding new map-like or Mapbox-backed fields, follow the same pattern: $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 with splitting: 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 Filament x-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 &lt;head&gt;.
  • Livewire partial — hidden data-fff-asset-batch marker (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 / ready classes),
  • managed links (data-fff-managed-asset) with CRG refCount uninstall,
  • scheduleResyncFromDom rAF coalescing,
  • protected links (data-fff-playground-bundle, flex-fields-core.css only).
After modifying JavaScript (including the injector):
Table column styles (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:
Enable the playground (local by default):
The playground renders live examples of every custom component and variant.

Rich card option shape

Used by ChoiceCards and ChoiceCheckboxCards via options().

Simple option

Rich option


Rich select option shape

Used by SelectField when options use a rich array shape or when richOptions() / optionLayout('grid') is enabled.

Simple option

Rich option

Option groups use nested arrays: 'Backend' =&gt; ['laravel' =&gt; 'Laravel', ...].

Dual listbox option shape

Used by DualListboxField via options().

Simple option

Rich option