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

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

1313 words

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:

Comments

Latest Posts

4 min

728 words

The Filament team has announced exciting details about the upcoming Filament v4 Beta release, and it’s undoubtedly the most anticipated version to date. Filament v4 is the largest and most feature-packed release Filament has ever had, surpassing even the massive v3 that required over 100 minor versions.

Most Notable Features of Filament v4

Nested Resources

One of the longest-standing community requests is finally becoming reality. Nested resources allow you to operate on a Filament resource within the context of a parent resource.

11 min

2211 words

How many times have you started a Laravel project manually creating models, controllers, migrations, factories, form requests, and tests one by one? If you’re like most Laravel developers, you’ve probably wasted countless hours on these repetitive tasks that, while necessary, don’t add direct value to your application’s business logic.

Laravel Blueprint is completely changing this paradigm. This code generation tool, created by Jason McCreary (the same genius behind Laravel Shift), allows you to generate multiple Laravel components from a single, readable, and expressive YAML file. In this deep analysis, we’ll explore how Blueprint can transform your development workflow and why it’s gaining traction in the Laravel community.

1 min

106 words

Options Pattern in Golang

Option pattern is a functional programming pattern that is used to provide optional arguments to a function that can be used to modify its behavior.

How to create a simple event streaming in Laravel?

Event streams provide you with a way to send events to the client without having to reload the page. This is useful for things like updating the user interface in real-time changes are made to the database.

6 min

1149 words

Idempotency in Laravel: How to Avoid Duplicates in Your APIs with Elegance

In modern API development, one of the most critical challenges is ensuring that operations don’t execute multiple times accidentally. Imagine a user making a payment and, due to connectivity issues, clicking the “Pay” button multiple times. Without proper measures, you might process multiple payments for the same transaction. This is where idempotency comes into play.

What is Idempotency?

Idempotency is a mathematical concept applied to programming that guarantees that an operation produces the same result regardless of how many times it’s executed. In the context of APIs, it means you can make the same request multiple times without causing additional side effects.

2 min

392 words

Laravel, in addition to using multiple third-party packages, is also possible to use parts as components. All components are under the “Illuminate” namespace.

If there’s a really interesting and useful class, it’s Collection, which allows us to work with data arrays in a simple and “programmatic” way.

To have this class in our project, we only need the illuminate/support package which we can install with:

composer require illuminate/support:5.2.x-dev

To show some examples, we’ll use a small array with this data: