Building Admin Panels with Filament: From Setup to Production
Why Filament?
Filament has revolutionized admin panel development in Laravel. Where we once spent weeks building CRUD interfaces, Filament delivers production-ready admin panels in hours. It's built on Livewire and Alpine.js, providing a reactive experience without writing JavaScript.
Setting Up Filament
Installation is straightforward:
composer require filament/filament
php artisan filament:install --panels
php artisan make:filament-user
Creating Resources
Resources are the heart of Filament—they define how models are displayed, created, and edited:
php artisan make:filament-resource Order --generate
This generates a resource with form and table schemas based on your model's fillable attributes. From there, customize to your needs:
class OrderResource extends Resource
{
protected static ?string $model = Order::class;
protected static ?string $navigationIcon = 'heroicon-o-shopping-cart';
protected static ?string $navigationGroup = 'Sales';
public static function form(Form $form): Form
{
return $form->schema([
Forms\Components\Section::make('Order Details')->schema([
Forms\Components\Select::make('customer_id')
->relationship('customer', 'name')
->searchable()
->preload()
->required(),
Forms\Components\Select::make('status')
->options([
'pending' => 'Pending',
'processing' => 'Processing',
'shipped' => 'Shipped',
'delivered' => 'Delivered',
])
->required(),
Forms\Components\DatePicker::make('order_date')
->default(now())
->required(),
])->columns(3),
Forms\Components\Section::make('Items')->schema([
Forms\Components\Repeater::make('items')
->relationship()
->schema([
Forms\Components\Select::make('product_id')
->relationship('product', 'name')
->searchable()
->required()
->reactive()
->afterStateUpdated(fn ($state, callable $set) =>
$set('unit_price', Product::find($state)?->price ?? 0)
),
Forms\Components\TextInput::make('quantity')
->numeric()
->default(1)
->required(),
Forms\Components\TextInput::make('unit_price')
->numeric()
->prefix('$')
->disabled(),
])->columns(3),
]),
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('id')
->sortable(),
Tables\Columns\TextColumn::make('customer.name')
->searchable(),
Tables\Columns\BadgeColumn::make('status')
->colors([
'warning' => 'pending',
'primary' => 'processing',
'success' => fn ($state) => in_array($state, ['shipped', 'delivered']),
]),
Tables\Columns\TextColumn::make('total')
->money('USD')
->sortable(),
Tables\Columns\TextColumn::make('created_at')
->dateTime()
->sortable(),
])
->filters([
Tables\Filters\SelectFilter::make('status')
->options([
'pending' => 'Pending',
'processing' => 'Processing',
'shipped' => 'Shipped',
'delivered' => 'Delivered',
]),
Tables\Filters\Filter::make('high_value')
->query(fn ($query) => $query->where('total', '>', 1000)),
])
->actions([
Tables\Actions\EditAction::make(),
Tables\Actions\Action::make('ship')
->action(fn (Order $record) => $record->update(['status' => 'shipped']))
->requiresConfirmation()
->visible(fn (Order $record) => $record->status === 'processing'),
]);
}
}
Custom Pages and Widgets
Filament makes it easy to add dashboard widgets:
class SalesOverview extends Widget
{
protected function getCards(): array
{
return [
Card::make('Total Revenue', '$' . number_format(Order::sum('total'), 2)),
Card::make('Orders This Month', Order::whereMonth('created_at', now())->count()),
Card::make('Average Order Value', '$' . number_format(Order::avg('total'), 2)),
];
}
}
Authorization
Integrate with Laravel's policies for fine-grained access control:
class OrderPolicy
{
public function viewAny(User $user): bool
{
return $user->hasPermission('orders.view');
}
public function update(User $user, Order $order): bool
{
return $user->hasPermission('orders.edit')
&& ($user->isAdmin() || $order->assigned_to === $user->id);
}
}
Conclusion
Filament transforms admin panel development from a chore into a pleasure. Its declarative approach, combined with Livewire's reactivity, delivers powerful interfaces with minimal code. Start with the generated resources and customize from there—you'll be amazed at what you can build in an afternoon.
Related Articles
Need Help With Your Project?
I respond to all inquiries within 24 hours. Let's discuss how I can help build your production-ready system.
Get In Touch