filament-expert
Filament 4 admin panel patterns including Resources, Forms, Tables, Widgets, Panels, and performance optimization.
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
メニュー
Filament 4 admin panel patterns including Resources, Forms, Tables, Widgets, Panels, and performance optimization.
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
PHP Artisan CLI patterns including make commands, flags, custom commands, and AI-friendly usage.
Advanced Eloquent ORM patterns including relationships, eager loading, factories, and query optimization.
Laravel development best practices covering service providers, dependency injection, facades, and the Laravel Way.
Laravel Tinker best practices for debugging, testing ideas, and data exploration. When and how to use safely.
Laravel-native error handling patterns. Renderable exceptions, Livewire traits strategies, and user-facing notifications.
Integrate Anthropic Claude API with Laravel. HTTP client, message format, error handling. Use when calling Claude models from Laravel applications.
SOC 職業分類に基づく
| name | filament-expert |
| description | Filament 4 admin panel patterns including Resources, Forms, Tables, Widgets, Panels, and performance optimization. |
Server-Driven UI framework for Laravel admin panels, built on Livewire, Alpine.js, and Tailwind CSS.
# Install Filament
composer require filament/filament:"^4.0"
# Create a panel
php artisan filament:install --panels
# Create a user
php artisan make:filament-user
⚠️ These changes from v3 to v4 are common sources of errors.
| Change | v3 | v4 |
|---|---|---|
| Layout Namespace | Forms\Components\{Grid,Section,Fieldset} | Filament\Schemas\Components\... |
| All Actions | Tables\Actions\* | Extend Filament\Actions\Action |
| Icons | String-based ('heroicon-o-plus') | Heroicon Enum |
| File Visibility | Public (default) | Private (default) |
| deferFilters | Opt-in | Default behavior |
| Grid/Section | Span all columns | Don't span by default |
// ❌ v3 (wrong in v4)
use Filament\Forms\Components\Grid;
use Filament\Forms\Components\Section;
// ✅ v4 (correct)
use Filament\Schemas\Components\Grid;
use Filament\Schemas\Components\Section;
php artisan make:filament-resource Post --generate
Creates:
app/Filament/Resources/PostResource.phpapp/Filament/Resources/PostResource/Pages/use Filament\Resources\Resource;
use Filament\Schemas\Components\Section;
use Filament\Schemas\Components\TextInput;
class PostResource extends Resource
{
protected static ?string $model = Post::class;
protected static ?string $navigationIcon = Heroicon::DocumentText;
public static function form(Form $form): Form
{
return $form->schema([
Section::make('Content')
->schema([
TextInput::make('title')
->required()
->maxLength(255),
RichEditor::make('body')
->required(),
]),
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
TextColumn::make('title')->searchable(),
TextColumn::make('created_at')->dateTime(),
])
->filters([
SelectFilter::make('status'),
])
->actions([
EditAction::make(),
DeleteAction::make(),
]);
}
}
// Resources can be deeply nested
PostResource::make()
->childResource(CommentResource::class);
TextInput::make('name')
->required()
->maxLength(255)
->placeholder('Enter name')
->helperText('This will be displayed publicly');
TextInput::make('price')
->numeric()
->prefix('$')
->suffix('USD');
TextInput::make('password')
->password()
->revealable();
Select::make('user_id')
->label('Author')
->relationship('author', 'name')
->searchable()
->preload()
->required();
Select::make('tags')
->relationship('tags', 'name')
->multiple()
->preload();
// Slider
Slider::make('rating')
->min(1)
->max(5)
->step(1);
// Code Editor
CodeEditor::make('code')
->language('php');
// Table Repeater
TableRepeater::make('items')
->schema([
TextInput::make('name'),
TextInput::make('quantity')->numeric(),
]);
Repeater::make('addresses')
->schema([
TextInput::make('street'),
TextInput::make('city'),
Select::make('country')
->options(Country::pluck('name', 'id')),
])
->columns(2)
->defaultItems(1)
->collapsible();
Replaces Trix with more features:
RichEditor::make('content')
->toolbarButtons([
'bold', 'italic', 'link', 'bulletList', 'orderedList',
'h2', 'h3', 'blockquote', 'codeBlock',
])
->extraAttributes(['class' => 'prose']);
RichEditor::make('email_template')
->mergeTags(['{{name}}', '{{email}}', '{{date}}']);
TextColumn::make('title')
->searchable()
->sortable()
->limit(50);
TextColumn::make('status')
->badge()
->color(fn (string $state) => match ($state) {
'draft' => 'gray',
'published' => 'success',
'archived' => 'danger',
});
ImageColumn::make('avatar')
->circular();
IconColumn::make('is_active')
->boolean();
Tables can use non-Eloquent data:
public function table(Table $table): Table
{
return $table
->query(fn () => collect($this->getApiData()))
->columns([...]);
}
SelectFilter::make('status')
->options([
'draft' => 'Draft',
'published' => 'Published',
]);
TernaryFilter::make('is_active');
Filter::make('created_at')
->form([
DatePicker::make('from'),
DatePicker::make('until'),
])
->query(fn (Builder $query, array $data) => $query
->when($data['from'], fn ($q, $date) => $q->whereDate('created_at', '>=', $date))
->when($data['until'], fn ($q, $date) => $q->whereDate('created_at', '<=', $date))
);
class StatsOverview extends BaseWidget
{
protected function getStats(): array
{
return [
Stat::make('Total Posts', Post::count())
->description('All time')
->descriptionIcon(Heroicon::ArrowTrendingUp)
->color('success'),
Stat::make('Pending', Post::pending()->count())
->color('warning'),
];
}
}
class PostsChart extends ChartWidget
{
protected static ?string $heading = 'Posts per Month';
protected function getData(): array
{
return [
'datasets' => [
[
'label' => 'Posts',
'data' => [10, 20, 30, 40, 50, 60],
],
],
'labels' => ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'],
];
}
protected function getType(): string
{
return 'bar';
}
}
// app/Providers/Filament/AdminPanelProvider.php
class AdminPanelProvider extends PanelProvider
{
public function panel(Panel $panel): Panel
{
return $panel
->id('admin')
->path('admin')
->login()
->colors(['primary' => Color::Amber])
->discoverResources(in: app_path('Filament/Resources'), for: 'App\\Filament\\Resources')
->discoverPages(in: app_path('Filament/Pages'), for: 'App\\Filament\\Pages')
->discoverWidgets(in: app_path('Filament/Widgets'), for: 'App\\Filament\\Widgets');
}
}
Reduce network requests with JS control:
// Hide field based on JS condition
TextInput::make('discount_code')
->hiddenJs('data.payment_method !== "credit_card"');
// JS callback after state update
Select::make('country')
->afterStateUpdatedJs('console.log("Country changed:", state)');
// In your Panel configuration
->mfa()
->totpEnabled()
->emailEnabled();
use function Livewire\livewire;
use Filament\Facades\Filament;
// For multi-panel, set current panel
Filament::setCurrentPanel('admin');
it('can list posts', function () {
$posts = Post::factory()->count(5)->create();
livewire(ListPosts::class)
->assertCanSeeTableRecords($posts)
->searchTable($posts->first()->title)
->assertCanSeeTableRecords($posts->take(1));
});
it('can create a post', function () {
livewire(CreatePost::class)
->fillForm([
'title' => 'My Post',
'body' => 'Content here',
])
->call('create')
->assertNotified()
->assertRedirect();
assertDatabaseHas(Post::class, ['title' => 'My Post']);
});
it('can send invoice', function () {
$invoice = Invoice::factory()->create();
livewire(EditInvoice::class, ['invoice' => $invoice])
->callAction('send');
expect($invoice->refresh())->isSent()->toBeTrue();
});
# Always use Filament's commands
php artisan make:filament-resource Post --generate
php artisan make:filament-page Settings
php artisan make:filament-widget StatsOverview --stats-overview
# Don't create files manually
relationship()// ✅ Use relationship() for auto-loading options
Select::make('user_id')
->relationship('author', 'name')
->required();
// ❌ Don't manually fetch options when relationship exists
Select::make('user_id')
->options(User::pluck('name', 'id'));
// Validate and authorize in actions
protected function mutateFormDataBeforeCreate(array $data): array
{
$this->authorize('create', Post::class);
return $data;
}
// Implement FilamentUser contract
class User extends Authenticatable implements FilamentUser
{
public function canAccessPanel(Panel $panel): bool
{
return $this->is_admin;
}
}
php artisan filament:optimize
php artisan icons:cache