Create FilamentPHP v4 tables with columns, filters, sorting, search, and bulk actions
Generates FilamentPHP v4 table configurations with columns, filters, and actions. Use when users request tables with search, sorting, bulk operations, or relationship displays.
/plugin marketplace add mwguerra/claude-code-plugins/plugin install post-development@mwguerra-marketplaceThis skill inherits all available tools. When active, it can use any tool Claude has access to.
This skill generates FilamentPHP v4 table configurations with columns, filters, actions, and bulk operations following official documentation patterns.
CRITICAL: Before generating tables, read:
/home/mwguerra/projects/mwguerra/claude-code-plugins/filament-specialist/skills/filament-docs/references/tables//home/mwguerra/projects/mwguerra/claude-code-plugins/filament-specialist/skills/filament-docs/references/tables/02-columns//home/mwguerra/projects/mwguerra/claude-code-plugins/filament-specialist/skills/filament-docs/references/tables/03-filters/Identify:
Navigate to table documentation and extract:
Build table configuration:
use Filament\Tables;
use Filament\Tables\Table;
public static function table(Table $table): Table
{
return $table
->columns([
// Columns
])
->filters([
// Filters
])
->actions([
// Row actions
])
->bulkActions([
// Bulk actions
]);
}
// Basic text
Tables\Columns\TextColumn::make('name')
->searchable()
->sortable();
// With limit and tooltip
Tables\Columns\TextColumn::make('description')
->limit(50)
->tooltip(fn ($record): string => $record->description);
// Formatted
Tables\Columns\TextColumn::make('price')
->money('usd')
->sortable();
// Date formatting
Tables\Columns\TextColumn::make('created_at')
->dateTime('M j, Y H:i')
->sortable()
->since(); // Shows "2 hours ago"
// Copyable
Tables\Columns\TextColumn::make('uuid')
->copyable()
->copyMessage('UUID copied!')
->copyMessageDuration(1500);
// With color
Tables\Columns\TextColumn::make('status')
->color(fn (string $state): string => match ($state) {
'draft' => 'gray',
'reviewing' => 'warning',
'published' => 'success',
default => 'gray',
});
// HTML content
Tables\Columns\TextColumn::make('content')
->html()
->wrap();
// Word/character count
Tables\Columns\TextColumn::make('bio')
->words(10);
// List values (array)
Tables\Columns\TextColumn::make('tags')
->listWithLineBreaks()
->bulleted();
// Boolean icon
Tables\Columns\IconColumn::make('is_active')
->boolean();
// Custom icons
Tables\Columns\IconColumn::make('status')
->icon(fn (string $state): string => match ($state) {
'draft' => 'heroicon-o-pencil',
'reviewing' => 'heroicon-o-clock',
'published' => 'heroicon-o-check-circle',
})
->color(fn (string $state): string => match ($state) {
'draft' => 'info',
'reviewing' => 'warning',
'published' => 'success',
default => 'gray',
});
// Basic image
Tables\Columns\ImageColumn::make('avatar')
->circular()
->size(40);
// Multiple images (stacked)
Tables\Columns\ImageColumn::make('images')
->circular()
->stacked()
->limit(3)
->limitedRemainingText();
// With default
Tables\Columns\ImageColumn::make('logo')
->defaultImageUrl(url('/images/default-logo.png'))
->square()
->size(60);
Tables\Columns\BadgeColumn::make('status')
->colors([
'danger' => 'draft',
'warning' => 'reviewing',
'success' => 'published',
])
->icons([
'heroicon-o-pencil' => 'draft',
'heroicon-o-clock' => 'reviewing',
'heroicon-o-check' => 'published',
]);
// Or with closure
Tables\Columns\BadgeColumn::make('priority')
->color(fn (string $state): string => match ($state) {
'low' => 'gray',
'medium' => 'warning',
'high' => 'danger',
});
Tables\Columns\ColorColumn::make('color')
->copyable()
->copyMessage('Color code copied');
// Editable inline toggle
Tables\Columns\ToggleColumn::make('is_active')
->onColor('success')
->offColor('danger')
->afterStateUpdated(fn () => Notification::make()
->title('Status updated')
->success()
->send()
);
// Editable inline select
Tables\Columns\SelectColumn::make('status')
->options([
'draft' => 'Draft',
'published' => 'Published',
]);
// Editable inline text
Tables\Columns\TextInputColumn::make('sort_order')
->rules(['required', 'numeric']);
// Editable inline checkbox
Tables\Columns\CheckboxColumn::make('is_featured');
// BelongsTo
Tables\Columns\TextColumn::make('author.name')
->label('Author')
->searchable()
->sortable();
// HasMany count
Tables\Columns\TextColumn::make('comments_count')
->counts('comments')
->label('Comments')
->sortable();
// HasMany sum
Tables\Columns\TextColumn::make('items_sum_quantity')
->sum('items', 'quantity')
->label('Total Quantity');
// BelongsToMany list
Tables\Columns\TextColumn::make('tags.name')
->badge()
->separator(',');
Tables\Columns\ViewColumn::make('custom')
->view('filament.tables.columns.custom-column');
Tables\Columns\TextColumn::make('name')
// Search
->searchable()
->searchable(isIndividual: true)
// Sort
->sortable()
->sortable(['first_name', 'last_name'])
// Visibility
->toggleable()
->toggleable(isToggledHiddenByDefault: true)
->visible(fn (): bool => auth()->user()->isAdmin())
->hidden(fn ($record): bool => $record->is_private)
// Sizing
->grow(false)
->width('200px')
->alignCenter()
->alignEnd()
// Styling
->weight(FontWeight::Bold)
->size(TextColumn\TextColumnSize::Large)
->color('primary')
->extraAttributes(['class' => 'custom-class']);
Tables\Filters\SelectFilter::make('status')
->options([
'draft' => 'Draft',
'reviewing' => 'Reviewing',
'published' => 'Published',
]);
// Multiple selection
Tables\Filters\SelectFilter::make('status')
->multiple()
->options([
'draft' => 'Draft',
'published' => 'Published',
]);
// Relationship filter
Tables\Filters\SelectFilter::make('author')
->relationship('author', 'name')
->searchable()
->preload();
Tables\Filters\TernaryFilter::make('is_active')
->label('Active')
->boolean()
->trueLabel('Active only')
->falseLabel('Inactive only')
->native(false);
Tables\Filters\Filter::make('created_at')
->form([
Forms\Components\DatePicker::make('created_from'),
Forms\Components\DatePicker::make('created_until'),
])
->query(function (Builder $query, array $data): Builder {
return $query
->when(
$data['created_from'],
fn (Builder $query, $date): Builder => $query->whereDate('created_at', '>=', $date),
)
->when(
$data['created_until'],
fn (Builder $query, $date): Builder => $query->whereDate('created_at', '<=', $date),
);
})
->indicateUsing(function (array $data): array {
$indicators = [];
if ($data['created_from'] ?? null) {
$indicators['created_from'] = 'From ' . Carbon::parse($data['created_from'])->toFormattedDateString();
}
if ($data['created_until'] ?? null) {
$indicators['created_until'] = 'Until ' . Carbon::parse($data['created_until'])->toFormattedDateString();
}
return $indicators;
});
Tables\Filters\TrashedFilter::make();
Tables\Filters\QueryBuilder::make()
->constraints([
Tables\Filters\QueryBuilder\Constraints\TextConstraint::make('name'),
Tables\Filters\QueryBuilder\Constraints\NumberConstraint::make('price'),
Tables\Filters\QueryBuilder\Constraints\DateConstraint::make('created_at'),
Tables\Filters\QueryBuilder\Constraints\RelationshipConstraint::make('author')
->icon('heroicon-o-user')
->multiple(),
]);
->actions([
Tables\Actions\ViewAction::make(),
Tables\Actions\EditAction::make(),
Tables\Actions\DeleteAction::make()
->requiresConfirmation(),
// Custom action
Tables\Actions\Action::make('publish')
->icon('heroicon-o-check')
->color('success')
->requiresConfirmation()
->action(fn (Model $record) => $record->publish())
->visible(fn (Model $record): bool => $record->status === 'draft'),
// Action with modal form
Tables\Actions\Action::make('send_email')
->icon('heroicon-o-envelope')
->form([
Forms\Components\TextInput::make('subject')
->required(),
Forms\Components\RichEditor::make('body')
->required(),
])
->action(function (Model $record, array $data): void {
Mail::to($record->email)->send(new CustomEmail($data));
}),
// Grouped actions
Tables\Actions\ActionGroup::make([
Tables\Actions\ViewAction::make(),
Tables\Actions\EditAction::make(),
Tables\Actions\DeleteAction::make(),
])->dropdown(),
// Replicate action
Tables\Actions\ReplicateAction::make()
->excludeAttributes(['slug', 'published_at'])
->beforeReplicaSaved(function (Model $replica): void {
$replica->name = $replica->name . ' (Copy)';
}),
]);
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
Tables\Actions\ForceDeleteBulkAction::make(),
Tables\Actions\RestoreBulkAction::make(),
// Custom bulk action
Tables\Actions\BulkAction::make('publish')
->icon('heroicon-o-check')
->requiresConfirmation()
->action(fn (Collection $records) => $records->each->publish())
->deselectRecordsAfterCompletion(),
// Export bulk action
Tables\Actions\BulkAction::make('export')
->icon('heroicon-o-arrow-down-tray')
->action(fn (Collection $records) => static::export($records)),
]),
]);
->headerActions([
Tables\Actions\CreateAction::make(),
Tables\Actions\AttachAction::make()
->preloadRecordSelect(),
// Import action
Tables\Actions\Action::make('import')
->icon('heroicon-o-arrow-up-tray')
->form([
Forms\Components\FileUpload::make('file')
->acceptedFileTypes(['text/csv']),
])
->action(fn (array $data) => static::import($data['file'])),
]);
public static function table(Table $table): Table
{
return $table
->columns([...])
->filters([...])
->actions([...])
->bulkActions([...])
// Pagination
->paginated([10, 25, 50, 100])
->defaultPaginationPageOption(25)
// Default sort
->defaultSort('created_at', 'desc')
// Reordering
->reorderable('sort_order')
->defaultSort('sort_order')
// Grouping
->groups([
Tables\Grouping\Group::make('status')
->label('Status')
->collapsible(),
Tables\Grouping\Group::make('author.name')
->label('Author'),
])
// Striped rows
->striped()
// Poll for updates
->poll('10s')
// Empty state
->emptyStateHeading('No posts yet')
->emptyStateDescription('Create your first post to get started.')
->emptyStateIcon('heroicon-o-document-text')
->emptyStateActions([
Tables\Actions\CreateAction::make()
->label('Create Post'),
])
// Modals
->modals([
'view' => true,
])
// Persist filters
->filtersFormColumns(3)
->persistFiltersInSession();
}
Generated tables include:
Creating algorithmic art using p5.js with seeded randomness and interactive parameter exploration. Use this when users request creating art using code, generative art, algorithmic art, flow fields, or particle systems. Create original algorithmic art rather than copying existing artists' work to avoid copyright violations.
Applies Anthropic's official brand colors and typography to any sort of artifact that may benefit from having Anthropic's look-and-feel. Use it when brand colors or style guidelines, visual formatting, or company design standards apply.
Create beautiful visual art in .png and .pdf documents using design philosophy. You should use this skill when the user asks to create a poster, piece of art, design, or other static piece. Create original visual designs, never copying existing artists' work to avoid copyright violations.