Filament v4 Beta: Comprehensive Analysis of the Revolutionary Features That Will Transform Laravel Application Development

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:

  • DateTimePicker
  • TextColumn with dates
  • TextEntry with 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 CourseLessons, 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

  1. Full pages: Instead of limited modals
  2. Better UX: More intuitive navigation
  3. Clear context: Always know which course you’re in
  4. 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 text
  • Button - Interactive buttons
  • Icon - Standalone icons
  • Link - Links

Layout Components:

  • Grid - Grid layouts
  • Flex - Flexible layouts
  • Stack - Vertical/horizontal stacking
  • Split - 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: