From filament-specialist
Generates FilamentPHP v4 actions for resources, pages, and tables including modals, confirmations, forms, and bulk operations.
How this skill is triggered — by the user, by Claude, or both
Slash command
/filament-specialist:actionsThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
This skill generates FilamentPHP v4 actions for resources, pages, and tables including modal actions, form actions, bulk operations, and custom workflows.
This skill generates FilamentPHP v4 actions for resources, pages, and tables including modal actions, form actions, bulk operations, and custom workflows.
CRITICAL: Before generating actions, read:
/home/mwguerra/projects/mwguerra/claude-code-plugins/filament-specialist/skills/docs/references/actions/use Filament\Actions;
// Create action
Actions\CreateAction::make()
->label('New Post')
->icon('heroicon-o-plus');
// Edit action
Actions\EditAction::make()
->label('Edit')
->icon('heroicon-o-pencil');
// View action
Actions\ViewAction::make()
->label('View Details')
->icon('heroicon-o-eye');
// Delete action
Actions\DeleteAction::make()
->requiresConfirmation()
->modalHeading('Delete post')
->modalDescription('Are you sure you want to delete this post? This action cannot be undone.')
->modalSubmitActionLabel('Yes, delete');
// Force delete (soft deletes)
Actions\ForceDeleteAction::make()
->requiresConfirmation();
// Restore (soft deletes)
Actions\RestoreAction::make();
// Simple confirmation action
Actions\Action::make('publish')
->label('Publish')
->icon('heroicon-o-check-circle')
->color('success')
->requiresConfirmation()
->modalHeading('Publish Post')
->modalDescription('Are you sure you want to publish this post?')
->modalSubmitActionLabel('Yes, publish')
->action(function (Model $record): void {
$record->update(['status' => 'published', 'published_at' => now()]);
Notification::make()
->title('Post published')
->success()
->send();
});
// Action with form modal
Actions\Action::make('send_email')
->label('Send Email')
->icon('heroicon-o-envelope')
->color('info')
->form([
Forms\Components\TextInput::make('subject')
->label('Subject')
->required()
->maxLength(255),
Forms\Components\Select::make('template')
->label('Template')
->options([
'welcome' => 'Welcome Email',
'reminder' => 'Reminder',
'promotion' => 'Promotion',
])
->required(),
Forms\Components\RichEditor::make('body')
->label('Message')
->required()
->columnSpanFull(),
])
->action(function (Model $record, array $data): void {
Mail::to($record->email)->send(new CustomEmail(
subject: $data['subject'],
template: $data['template'],
body: $data['body'],
));
Notification::make()
->title('Email sent successfully')
->success()
->send();
});
// Wizard action (multi-step)
Actions\Action::make('create_order')
->label('Create Order')
->icon('heroicon-o-shopping-cart')
->steps([
Forms\Components\Wizard\Step::make('Customer')
->schema([
Forms\Components\Select::make('customer_id')
->relationship('customer', 'name')
->required()
->searchable(),
]),
Forms\Components\Wizard\Step::make('Products')
->schema([
Forms\Components\Repeater::make('items')
->schema([
Forms\Components\Select::make('product_id')
->relationship('product', 'name')
->required(),
Forms\Components\TextInput::make('quantity')
->numeric()
->required()
->default(1),
])
->columns(2),
]),
Forms\Components\Wizard\Step::make('Shipping')
->schema([
Forms\Components\Textarea::make('address')
->required(),
Forms\Components\Select::make('shipping_method')
->options([
'standard' => 'Standard',
'express' => 'Express',
]),
]),
])
->action(function (array $data): void {
Order::create($data);
});
Actions\Action::make('approve')
// Visible only for specific status
->visible(fn (Model $record): bool => $record->status === 'pending')
// Hidden in certain conditions
->hidden(fn (Model $record): bool => $record->is_archived)
// Authorization check
->authorize('approve')
// Or with closure
->authorized(fn (): bool => auth()->user()->can('approve_posts'));
// Action that refreshes data
Actions\Action::make('refresh')
->icon('heroicon-o-arrow-path')
->action(fn () => null) // No action needed
->after(fn ($livewire) => $livewire->dispatch('refresh'));
// Action with redirect
Actions\Action::make('view_invoice')
->icon('heroicon-o-document')
->url(fn (Model $record): string => route('invoices.show', $record->invoice_id))
->openUrlInNewTab();
// Action with download
Actions\Action::make('download_pdf')
->icon('heroicon-o-arrow-down-tray')
->action(function (Model $record) {
return response()->download(
storage_path("invoices/{$record->invoice_id}.pdf")
);
});
use Filament\Tables\Actions;
public static function table(Table $table): Table
{
return $table
->columns([...])
->actions([
// Icon-only actions
Actions\ActionGroup::make([
Actions\ViewAction::make(),
Actions\EditAction::make(),
Actions\DeleteAction::make(),
])->dropdownPlacement('bottom-end'),
// Or inline
Actions\ViewAction::make()
->iconButton(),
Actions\EditAction::make()
->iconButton(),
// Custom inline action
Actions\Action::make('duplicate')
->icon('heroicon-o-document-duplicate')
->iconButton()
->action(function (Model $record): void {
$replica = $record->replicate();
$replica->name = $record->name . ' (Copy)';
$replica->save();
}),
]);
}
use Filament\Tables\Actions;
->bulkActions([
Actions\BulkActionGroup::make([
// Standard bulk delete
Actions\DeleteBulkAction::make(),
// Custom bulk action
Actions\BulkAction::make('publish')
->label('Publish Selected')
->icon('heroicon-o-check-circle')
->color('success')
->requiresConfirmation()
->action(function (Collection $records): void {
$records->each->update(['status' => 'published']);
Notification::make()
->title(count($records) . ' posts published')
->success()
->send();
})
->deselectRecordsAfterCompletion(),
// Bulk action with form
Actions\BulkAction::make('assign_category')
->label('Assign Category')
->icon('heroicon-o-tag')
->form([
Forms\Components\Select::make('category_id')
->label('Category')
->relationship('category', 'name')
->required(),
])
->action(function (Collection $records, array $data): void {
$records->each->update(['category_id' => $data['category_id']]);
}),
// Export bulk action
Actions\BulkAction::make('export')
->label('Export to CSV')
->icon('heroicon-o-arrow-down-tray')
->action(function (Collection $records) {
return Excel::download(
new RecordsExport($records),
'records.csv'
);
}),
]),
]);
use Filament\Tables\Actions;
->headerActions([
// Create action
Actions\CreateAction::make()
->label('New Post'),
// Import action
Actions\Action::make('import')
->label('Import')
->icon('heroicon-o-arrow-up-tray')
->form([
Forms\Components\FileUpload::make('file')
->label('CSV File')
->acceptedFileTypes(['text/csv'])
->required(),
])
->action(function (array $data): void {
// Import logic
}),
// Attach action (for relationships)
Actions\AttachAction::make()
->preloadRecordSelect()
->recordSelectSearchColumns(['name', 'email']),
]);
// In RelationManager class
protected function getHeaderActions(): array
{
return [
Tables\Actions\CreateAction::make(),
Tables\Actions\AttachAction::make()
->preloadRecordSelect()
->form(fn (Tables\Actions\AttachAction $action): array => [
$action->getRecordSelect(),
Forms\Components\TextInput::make('role')
->required(),
]),
Tables\Actions\AssociateAction::make(),
];
}
public function table(Table $table): Table
{
return $table
->columns([...])
->actions([
Tables\Actions\EditAction::make(),
Tables\Actions\DetachAction::make(),
Tables\Actions\DissociateAction::make(),
Tables\Actions\DeleteAction::make(),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DetachBulkAction::make(),
Tables\Actions\DeleteBulkAction::make(),
]),
]);
}
// In resource page classes
protected function getHeaderActions(): array
{
return [
Actions\EditAction::make(),
Actions\DeleteAction::make(),
// Custom action
Actions\Action::make('preview')
->icon('heroicon-o-eye')
->url(fn (): string => route('posts.show', $this->record))
->openUrlInNewTab(),
];
}
// For List page
protected function getHeaderActions(): array
{
return [
Actions\CreateAction::make(),
// Global action
Actions\Action::make('settings')
->icon('heroicon-o-cog')
->url(fn (): string => route('filament.admin.pages.settings')),
];
}
Actions\Action::make('custom')
// Label and icon
->label('Custom Action')
->icon('heroicon-o-star')
->iconPosition(IconPosition::After)
// Colors
->color('success') // primary, secondary, success, warning, danger, info, gray
// Size
->size(ActionSize::Large)
// Button style
->button()
->outlined()
->iconButton()
->link()
// Keyboard shortcut
->keyBindings(['mod+s'])
// Extra attributes
->extraAttributes([
'class' => 'my-custom-class',
'data-action' => 'custom',
])
// Badge
->badge(fn () => 5)
->badgeColor('danger')
// Tooltip
->tooltip('Click to perform action');
use Filament\Notifications\Notification;
use Filament\Notifications\Actions\Action;
Notification::make()
->title('Post created successfully')
->success()
->body('Your post has been created.')
->actions([
Action::make('view')
->button()
->url(route('posts.show', $record)),
Action::make('undo')
->color('gray')
->action(fn () => $record->delete()),
])
->send();
Generated actions include:
npx claudepluginhub mwguerra/claude-code-plugins --plugin filament-specialistGenerates FilamentPHP v4 resources including form schemas, tables, relation managers, and actions for Laravel admin panels. Use when extending Filament with custom resources.
Implements Next.js Server Actions for server mutations: 'use server' definitions, form handling with useActionState/useFormStatus, optimistic updates via useOptimistic, Zod/next-safe-action validation, file uploads, authorization, and revalidation.
Guides creation of custom Backpex item actions for table rows, show pages, and index toolbars, with support for server-side handle/3, client-side link/2, optional form modals, and confirm dialogs.