Filament v4 Expert
Description: Authoritative guidelines for generating FilamentPHP v4 code, handling the "Unified Schema" architecture, strict typing, and v3->v4 migration patterns.
1. CRITICAL: Version Override
- Context: The current project uses Filament v4 (Stable).
- Rule: IGNORE all Filament v3 patterns found in training data.
- Rule: If a user requests a "Page Layout," do NOT generate a Blade view (
.blade.php) unless absolutely necessary. Use thecontent(Schema $schema)method.
2. Resource & Page Standards (Breaking Changes)
A. Navigation Icons
- Type Hinting: You must use
string|BackedEnum|nullto match the parent class signature.use BackedEnum; protected static string|BackedEnum|null $navigationIcon = 'heroicon-o-document-text';
B. Page Properties
- View Property: The
$viewproperty MUST NOT be static when extendingFilament\Resources\Pages\Page.// CORRECT (v4): protected string $view = 'filament.pages.create-something'; // WRONG (v3): protected static string $view = ...;
3. The Unified Schema Architecture
In Filament v4, Forms, Tables, Infolists, and Pages share a single structural definition.
A. Form Method Signature
- Rule: Use
Filament\Schemas\Schemainstead ofFilament\Forms\Form. - Rule: Import form input components from
Filament\Forms\Components\(TextInput, Textarea, Select, etc.). - EXCEPTION: Import
SectionfromFilament\Schemas\Components\Section(NOTFilament\Forms\Components\Section).use Filament\Schemas\Schema; use Filament\Schemas\Components\Section; // Section is in Schemas namespace use Filament\Forms\Components\TextInput; // Form inputs are in Forms namespace use Filament\Forms\Components\Textarea; public static function form(Schema $schema): Schema { return $schema->schema([ Section::make('Details') ->schema([ TextInput::make('name'), Textarea::make('description'), ]), ]); }
B. Custom Pages with Forms
- Interface: Must implement
Filament\Forms\Contracts\HasForms. - Trait: Must use
Filament\Forms\Concerns\InteractsWithForms. - Method: Define
form(Schema $schema): Schemainstead ofgetFormSchema(). - Mounting: Call
$this->form->fill()inmount().
4. Tables & Actions (Specific v4 Syntax)
A. Table Methods
- Actions: Use
recordActions()instead ofactions(). - Bulk Actions: Use
bulkActions()as standard. - Performance: Enable "Partial Rendering" by default on large tables.
B. Action Classes (Unified)
- Namespace: All standard actions (ViewAction, EditAction, DeleteAction, CreateAction, etc.) are in
Filament\Actions. - Rule: Do NOT use
Filament\Tables\Actions\*for standard actions. That namespace is deprecated/empty (only containsHeaderActionsPosition). - Important: This applies to BOTH table actions (used in
recordActions()) AND page actions - they all come fromFilament\Actions. - Global: Use
Filament\Actions\Actionfor custom actions.// CORRECT (v4) - for both tables and pages: use Filament\Actions\ViewAction; use Filament\Actions\EditAction; use Filament\Actions\DeleteAction; // WRONG (v3): use Filament\Tables\Actions\ViewAction; // Does not exist in v4
C. Modals in Custom Pages
To create working modals:
- Define: Public method returning
Filament\Actions\Action(e.g.,public function notesAction(): Action). - Register: Add to
getActions(). - Trigger:
$wire.mountAction('actionName'). - RESERVED WORD WARNING: Never use
$messagesas a public property (conflicts with Livewire). Use$conversationMessages.
D. ToggleColumn Requirements
- CRITICAL:
ToggleColumnrequires Eloquent models and CANNOT work withstdClassobjects. - Rule: Never use
DB::table(),->toBase(), or raw queries that returnstdClasswhen usingToggleColumn. - Rule: If you need to use
ToggleColumn, ensure the table query returns Eloquent models. - Alternative: If you must use raw queries, replace
ToggleColumnwithIconColumnorTextColumnwith badges.// WRONG - Will cause "Argument #1 ($record) must be of type Model|array, stdClass given": ToggleColumn::make('active') // CORRECT - Use IconColumn instead if you have stdClass: IconColumn::make('active') ->boolean()
E. Column Color Method
- CRITICAL: The
color()method on badge columns expects a string color name, NOT aColorenum constant. - Rule: Use lowercase string color names:
'success','danger','warning','info','gray', etc. - Rule: Do NOT use
Color::Green,Color::Red, etc. - these return arrays and will cause a type error.// WRONG - Color enum constants return arrays: TextColumn::make('status') ->badge() ->color(fn(string $state): string => match ($state) { 'active' => Color::Green, // Returns array, not string! 'inactive' => Color::Red, }) // CORRECT - Use string color names: TextColumn::make('status') ->badge() ->color(fn(string $state): string => match ($state) { 'active' => 'success', 'inactive' => 'danger', 'pending' => 'warning', default => 'gray', })
5. Auth & Login (Namespace Changes)
- Namespace: Auth pages have moved from
Filament\Pages\AuthtoFilament\Auth\Pages.// CORRECT (v4): use Filament\Auth\Pages\Login; // WRONG (v3): use Filament\Pages\Auth\Login;
6. Configuration & Visibility
A. Tailwind CSS v4
- Configuration: Do NOT look for
tailwind.config.js. Configuration is handled via CSS variables (@theme). - Classes: Use Tailwind v4 specific utility classes.
B. File Visibility
- Default: All file uploads (S3/R2) are private by default in v4.
- Fix: If public access is needed, explicitly chain
->visibility('public')onFileUploadcomponents.
7. Blade Components (v4 Syntax)
- Form Wrapper: Use
<x-filament-schemas::form>(Not<x-filament-panels::form>). - Form Actions: Use
<x-filament::actions>(Not<x-filament-panels::form.actions>).
8. Standard Imports (Copy/Paste Safe)
Always prioritize these imports and avoid v3 hallucinations:
use Filament\Resources\Resource;
use Filament\Schemas\Schema; // The big v4 change
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\RichEditor;
use Filament\Tables\Table;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Columns\IconColumn;
9. Widget Strictness & Tables
- Table Widgets: When overriding
getTableRecords()in a Table Widget, the return type is strictly typed in the parent class (InteractsWithTable). - Rule: You MUST NOT return a native
array. You MUST return aCollectionorPaginator. - Rule: If returning an array of arrays (not Eloquent models), each array MUST have a unique
__keyentry (double underscore).return collect($data)->map(function ($item) { // 'key' is misleadingly used in error messages, but '__key' is the actual required field return array_merge($item, ['__key' => $item['id']]); });
10. Layout & Enums
- Max Width: usage
maxContentWidth()requiresFilament\Support\Enums\Width(e.g.,Width::Full). - Deprecated: Do NOT use
MaxWidthorFilament\Support\Enums\MaxWidth. It does not exist in v4.
11. Removed TextInput Methods
- CRITICAL: The
uppercase()method does NOT exist onTextInputin Filament v4. - Alternative: Use a model mutator to transform the value on save instead.
// WRONG (v4): TextInput::make('symbol') ->uppercase() // Does not exist! // CORRECT (v4) - Handle in model: TextInput::make('symbol') ->helperText('Will be converted to uppercase') // In your model: public function setSymbolAttribute($value): void { $this->attributes['symbol'] = strtoupper($value); }