Dynamic Form Behavior
Filament's true power emerges when forms respond intelligently to user interactions, creating seamless and intuitive user experiences that adapt in real-time. Unlike static forms that remain unchanged after rendering, Filament leverages Livewire's reactivity to build forms that can show or hide fields, update options dynamically, auto-generate content, and provide instant feedback—all without requiring a full page reload.
# Basic Field Visibility Control
Control when fields appear in your forms using server-side PHP callbacks that evaluate the current form state. This approach provides the most flexibility for complex conditional logic while maintaining type safety and access to all PHP utilities and database queries.
use Filament\Forms\Get;
use Filament\Forms\Components\Checkbox;
use Filament\Forms\Components\TextInput;
Checkbox::make('is_company')
->label('Register as company')
->live(), // Required for reactivity
TextInput::make('company_name')
->label('Company Name')
->visible(fn (Get $get): bool => $get('is_company'))
->required(fn (Get $get): bool => $get('is_company')),
TextInput::make('vat_number')
->label('VAT Number')
->hidden(fn (Get $get): bool => !$get('is_company'))
->required(fn (Get $get): bool => $get('is_company')),
# Live field updates with smart debouncing
Configure how and when form fields trigger updates using live() method variations that balance responsiveness with performance. The live() method can be fine-tuned to trigger updates immediately, on blur, or after a custom debounce delay, giving you complete control over the user experience.
use Filament\Forms\Components\Select;
use Filament\Forms\Get;
use Filament\Forms\Set;
use Illuminate\Support\Collection;
Select::make('category_id')
->label('Main Category')
->options(Category::whereNull('parent_id')->pluck('name', 'id'))
->live()
->afterStateUpdated(fn (Set $set) => $set('subcategory_id', null)),
Select::make('subcategory_id')
->label('Subcategory')
->options(fn (Get $get): Collection =>
Category::query()
->where('parent_id', $get('category_id'))
->pluck('name', 'id')
)
->disabled(fn (Get $get): bool => blank($get('category_id')))
->placeholder(fn (Get $get): string =>
blank($get('category_id'))
? 'First select a main category'
: 'Select a subcategory'
),
# Auto-generated fields with intelligent updates
Automatically populate field values based on other inputs using afterStateUpdated hooks that run custom logic whenever dependencies change. This feature is essential for creating user-friendly forms that reduce manual data entry and ensure consistency across related fields.
use Filament\Forms\Components\TextInput;
use Filament\Forms\Set;
use Illuminate\Support\Str;
TextInput::make('title')
->live(onBlur: true)
->afterStateUpdated(function (Set $set, ?string $state) {
// Auto-generate slug from title
$set('slug', Str::slug($state));
}),
TextInput::make('slug')
->disabled()
->dehydrated(), // Include in form data even though disabled
TextInput::make('price')
->numeric()
->live(onBlur: true)
->afterStateUpdated(function (Set $set, ?string $state, Get $get) {
$taxRate = $get('tax_rate') ?? 0.20;
$priceWithTax = $state * (1 + $taxRate);
$set('price_with_tax', number_format($priceWithTax, 2));
}),
TextInput::make('price_with_tax')
->disabled()
->dehydrated()