The Filament v4 Beta has officially arrived, and it’s undoubtedly the most ambitious and comprehensive update in this framework’s history. After exploring in detail all the new features, I can confidently say that this version represents a quantum leap in terms of performance, ease of use, and development capabilities.
In this comprehensive analysis, we’ll explore each of the new features in Filament v4, explaining not just what’s new, but also how these improvements can transform your workflow and your application possibilities.
Performance: The Invisible Revolution
Rendering Optimizations
One of the most significant, though less visible, improvements is the massive rendering performance optimization. Filament v4 has internally rewritten many Blade templates to dramatically reduce the number of views being rendered.
How did they achieve it?
- Using existing PHP objects to render HTML instead of including new files
- Reducing the number of files that need to be loaded
- Extracting Tailwind CSS class groups into dedicated classes
- Minimizing the amount of HTML that needs to be rendered
The result: Faster pages, smaller response sizes, and better user experience, especially noticeable in large tables with many records.
Specific Table Improvements
Tables have received special attention in terms of performance:
// Before: Slow processing with many records
Table::make()
->columns([
TextColumn::make('name'),
TextColumn::make('email'),
// ... many more columns
])
->records($thousandsOfRecords); // Slow in v3
// Now: Automatically optimized rendering in v4
Table::make()
->columns([
TextColumn::make('name'),
TextColumn::make('email'),
// ... same columns, but much faster
])
->records($thousandsOfRecords); // Optimized in v4
Tailwind CSS v4: The Future of Web Design
Modernized Color System
Filament v4 adopts Tailwind CSS v4, which includes a revolutionary shift from RGB color space to OKLCH, using the broader P3 color gamut to produce more vibrant and accurate colors.
/* Before (RGB) */
.bg-blue-500 { background-color: rgb(59 130 246); }
/* Now (OKLCH) */
.bg-blue-500 { background-color: oklch(0.7 0.15 252); }
Benefits of the new system:
- More vibrant colors: Takes advantage of P3 color space
- Better consistency: More uniform luminosity perception
- Better accessibility: Improved compliance with WCAG guidelines
Simplified Configuration
Tailwind v4 introduces a revamped configuration system that’s more intuitive and powerful:
// tailwind.config.js (v4)
export default {
content: ['./src/**/*.{html,js,php}'],
theme: {
extend: {
colors: {
brand: 'oklch(0.7 0.15 252)'
}
}
}
}
Multi-Factor Authentication (MFA): Enterprise-Grade Security
Simple Setup
Implementing MFA in Filament v4 is surprisingly simple:
use Filament\Auth\MultiFactor\App\AppAuthentication;
use Filament\Auth\MultiFactor\Email\EmailAuthentication;
public function panel(Panel $panel): Panel
{
return $panel
->multiFactorAuthentication([
AppAuthentication::make(),
EmailAuthentication::make()->codeExpiryMinutes(5),
], isRequired: true);
}
Available Methods
1. App Authentication:
- Compatible with Google Authenticator
- Support for Authy
- Microsoft Authenticator
- Any TOTP-compatible app
2. Email Authentication:
- One-time codes sent via email
- Configurable expiration time
- Customizable email templates
Extensibility
use Filament\Auth\MultiFactor\MfaProvider;
class SmsAuthentication extends MfaProvider
{
public function getId(): string
{
return 'sms';
}
public function getName(): string
{
return 'SMS Verification';
}
public function generateChallenge(User $user): string
{
$code = sprintf('%06d', mt_rand(0, 999999));
// Send SMS with $code
return $code;
}
public function verifyChallenge(User $user, string $code): bool
{
// Verify SMS code
return $this->isValidSmsCode($user, $code);
}
}
Heroicons: Goodbye to Magic Strings
Intelligent Autocomplete
The new Heroicon enum class provides full IDE autocomplete:
use Filament\Support\Enums\Heroicon;
// ❌ Before: Error-prone magic strings
Action::make('edit')
->icon('heroicon-o-pencil-square') // Easy to mistype
// ✅ Now: Autocomplete and type checking
Action::make('edit')
->icon(Heroicon::OutlinedPencilSquare) // IDE autocompletes
// Automatic variants
->icon(Heroicon::PencilSquare) // Solid
->icon(Heroicon::OutlinedPencilSquare) // Outlined
->icon(Heroicon::MiniPencilSquare) // Mini (16px)
Automatic Size Selection
Filament automatically selects the appropriate icon size based on context:
- 16px for small elements
- 20px for medium elements
- 24px for large elements
Global Timezone Configuration
FilamentTimezone Facade
use Filament\Support\Facades\FilamentTimezone;
// Global configuration in AppServiceProvider
public function boot(): void
{
FilamentTimezone::set('Europe/Madrid');
}
Affected Components
This configuration automatically impacts:
DateTimePickerTextColumnwith datesTextEntrywith dates- Any component handling dates/times
Standard ISO Formats
TextColumn::make('created_at')
->dateTime('iso') // Automatic ISO 8601 format
TextColumn::make('updated_at')
->date('iso-date') // ISO date only
Nested Resources: The Most Requested Feature
The Previous Problem
Before v4, if you had a structure like Course → Lessons, you could only edit lessons in modals within the course resource.
The Solution: Nested Resources
# Create a nested resource
php artisan make:filament-resource LessonResource --nested
Nested Resource Configuration
// app/Filament/Resources/LessonResource.php
class LessonResource extends Resource
{
protected static ?string $model = Lesson::class;
// Define parent relationship
public static function getParentResource(): ?string
{
return CourseResource::class;
}
public static function getParentRelationshipName(): string
{
return 'course';
}
public static function form(Form $form): Form
{
return $form
->schema([
TextInput::make('title')->required(),
Textarea::make('content'),
TimePicker::make('duration'),
FileUpload::make('video_file'),
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
TextColumn::make('title'),
TextColumn::make('duration'),
ToggleColumn::make('is_published'),
]);
}
}
Benefits of Nested Resources
- Full pages: Instead of limited modals
- Better UX: More intuitive navigation
- Clear context: Always know which course you’re in
- Full functionality: All features of normal resources
Unified Schemas: Server-Driven UI
Fundamental Concept
Schemas form the basis of Filament’s Server-Driven UI approach. They allow you to build interfaces in PHP using structured configuration objects.
use Filament\Schemas\Schema;
use Filament\Schemas\Components\Text;
use Filament\Schemas\Components\Button;
$schema = Schema::make()
->components([
Text::make('Main Title')
->size('xl')
->weight('bold'),
Text::make('Detailed content description')
->color('gray'),
Button::make('Main Action')
->color('primary')
->action(fn() => $this->doSomething()),
]);
Available Components
Prime Components:
Text- For displaying textButton- Interactive buttonsIcon- Standalone iconsLink- Links
Layout Components:
Grid- Grid layoutsFlex- Flexible layoutsStack- Vertical/horizontal stackingSplit- Screen division
Form Fields: All existing form fields
Infolist Entries: All infolist entry types
Page Customization
// Completely customize page layout
public function content(): array
{
return [
Grid::make(2)
->schema([
// Left column
Stack::make([
Text::make('Dashboard'),
$this->getInfolist(),
]),
// Right column
Stack::make([
Text::make('Quick Actions'),
$this->getActions(),
]),
]),
];
}
Form Improvements: Power and Flexibility
Rich Editor with Tiptap
The rich editor now uses Tiptap, a modern and extensible framework:
RichEditor::make('content')
->json() // Store as JSON instead of HTML
->customBlocks([
// Draggable custom blocks
'call_to_action' => [
'label' => 'Call to Action',
'schema' => [
TextInput::make('title'),
TextInput::make('button_text'),
TextInput::make('button_url'),
],
],
])
->mergeTags([
// Dynamic tags like {{ name }}
'user_name' => 'User Name',
'today' => 'Today\'s Date',
'company' => 'Company Name',
]);
Slider Component
Slider::make('rating')
->min(1)
->max(5)
->step(0.5)
->marks([1, 2, 3, 4, 5]) // Visible marks
->displayValue() // Show current value
->formatValue(fn($value) => $value . ' stars');
// Range slider
Slider::make('price_range')
->range() // Enable range mode
->min(0)
->max(1000)
->formatValue(fn($value) => '€' . number_format($value));
Code Editor
CodeEditor::make('custom_css')
->language('css')
->lineNumbers()
->theme('dark')
->height('300px');
CodeEditor::make('api_response')
->language('json')
->readonly()
->formatUsing(function ($state) {
return json_encode($state, JSON_PRETTY_PRINT);
});
Table Repeaters
Repeater::make('products')
->table() // Display as table
->schema([
TextInput::make('name'),
TextInput::make('price'),
Select::make('category'),
])
->table([
// Configure table columns
TableColumn::make('name')
->width('40%'),
TableColumn::make('price')
->width('20%')
->alignment('end'),
TableColumn::make('category')
->width('40%'),
]);
ModalTableSelect
Select::make('customer_id')
->modalTable() // Selection from modal table
->relationship('customer', 'name')
->modalTableColumns([
TextColumn::make('name'),
TextColumn::make('email'),
TextColumn::make('company'),
])
->modalTableFilters([
SelectFilter::make('company'),
])
->modalTableSearch();
Optimized JavaScript
// Visibility with JavaScript (no reload)
TextInput::make('other_reason')
->visibleJs("$get('reason') === 'other'") // Instant evaluation
// Dynamic content with JavaScript
Text::make()
->label(JsContent::make("'Total: $' + ($get('price') * $get('quantity'))"))
// Updates without reload
TextInput::make('quantity')
->afterStateUpdatedJs("$set('total', $get('price') * $state)")
FusedGroup
FusedGroup::make([
TextInput::make('first_name')
->placeholder('First name'),
TextInput::make('last_name')
->placeholder('Last name'),
])
->label('Full Name')
->columns(2);
Partial Rendering
TextInput::make('search')
->live()
->partiallyRenderComponentsAfterStateUpdated(['results_table']) // Only re-render table
Select::make('category')
->live()
->partiallyRenderAfterStateUpdated() // Only re-render this field
TextInput::make('notes')
->live()
->skipRenderAfterStateUpdated() // Don't re-render anything
Tables with Static Data: Complete Flexibility
Simple Data
Table::make()
->records([
['name' => 'John Doe', 'email' => 'john@example.com', 'role' => 'Admin'],
['name' => 'Jane Smith', 'email' => 'jane@example.com', 'role' => 'User'],
['name' => 'Bob Johnson', 'email' => 'bob@example.com', 'role' => 'Editor'],
])
->columns([
TextColumn::make('name')
->searchable()
->sortable(),
TextColumn::make('email'),
BadgeColumn::make('role')
->colors([
'success' => 'Admin',
'warning' => 'Editor',
'secondary' => 'User',
]),
]);
Conclusion
Filament v4 Beta represents much more than an incremental update; it’s a complete reimagining of what a web application development tool can be. Dan Harrin and the team have created something truly special that will change how we develop Laravel applications.
The beta is available now, and while it’s not yet production-stable, it’s the perfect time to explore these new capabilities and prepare for the future of Filament.
Have you tried Filament v4 Beta yet? What feature do you find most exciting? Share your experience in the comments!
Important links:












Comments