一键导入
tables
Create FilamentPHP v4 tables with columns, filters, sorting, search, and bulk actions
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Create FilamentPHP v4 tables with columns, filters, sorting, search, and bulk actions
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Analyze, test, and prepare apps for production with Pest and Playwright testing
This skill should be used when encountering errors during development, when the user mentions an error, when debugging issues, or when asked to "fix an error", "debug this", "why is this failing", "solve this error". Provides intelligent error recognition, solution lookup from past errors, and error logging for future reference.
This skill should be used when the user asks to "manage notes", "update vault", "add to obsidian", "document in vault", "search my notes", "find related notes", or when working with Obsidian vault files. Also triggers when discussing knowledge management, note organization, or when Claude Code auto-captures commits, tasks, or component creation.
This skill should be used when conducting PRD interviews, creating product requirements documents, planning new features, documenting bug fixes, or when using commands like "/prd-builder:prd", "/prd-builder:feature", "/prd-builder:bugfix", or "/prd-builder:refine". Provides comprehensive interview frameworks and question templates for building thorough PRDs.
Execute complete user flow testing with Playwright MCP, testing end-to-end journeys through the application
Systematically test all pages for errors, functionality, and proper rendering using Playwright MCP
| name | tables |
| description | Create FilamentPHP v4 tables with columns, filters, sorting, search, and bulk actions |
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/docs/references/tables//home/mwguerra/projects/mwguerra/claude-code-plugins/filament-specialist/skills/docs/references/tables/02-columns//home/mwguerra/projects/mwguerra/claude-code-plugins/filament-specialist/skills/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: