Agent Skillsrelaticle/relaticle › filament-development

filament-development

GitHub

用于构建和调试基于 Laravel Livewire 的 Filament 管理面板及界面。涵盖创建资源、表单、表格、页面等组件,支持使用 Artisan 命令生成代码及处理动态交互逻辑。

.claude/skills/filament-development/SKILL.md relaticle/relaticle

Trigger Scenarios

创建或修改 Filament 管理面板界面 调试 Filament 表单、表格或关系管理器 生成 Filament 资源文件

Install

npx skills add relaticle/relaticle --skill filament-development -g -y
More Options

Non-standard path

npx skills add https://github.com/relaticle/relaticle/tree/main/.claude/skills/filament-development -g -y

Use without installing

npx skills use relaticle/relaticle@filament-development

指定 Agent (Claude Code)

npx skills add relaticle/relaticle --skill filament-development -a claude-code -g -y

安装 repo 全部 skill

npx skills add relaticle/relaticle --all -g -y

预览 repo 内 skill

npx skills add relaticle/relaticle --list

SKILL.md

Frontmatter
{
    "name": "filament-development",
    "description": "Builds Filament application and admin panel interfaces. Use when creating, modifying, testing, or debugging Filament panels, resources, relation managers, pages, schemas, forms, tables, actions, infolists, widgets, imports, or exports."
}

Filament Development

  • Filament is a Laravel UI framework built on Livewire, Alpine.js, and Tailwind CSS. UIs are defined in PHP via fluent, chainable components. Follow existing conventions in this app.
  • Use the search-docs tool for official documentation on Artisan commands, code examples, testing, relationships, and idiomatic practices. If search-docs is unavailable, refer to https://filamentphp.com/docs.

Artisan

  • Always use Filament-specific Artisan commands to create files. Find available commands with the list-artisan-commands tool, or run php artisan list.
  • Inspect required options before running, and always pass --no-interaction.

Patterns

Always use static make() methods to initialize components. Most configuration methods accept a Closure for dynamic values.

Use Get $get to read other form field values for conditional logic:

Conditional form field visibility

use Filament\Forms\Components\Select;
use Filament\Forms\Components\TextInput;
use Filament\Schemas\Components\Utilities\Get;

Select::make('type')
    ->options(CompanyType::class)
    ->required()
    ->live(),

TextInput::make('company_name')
    ->required()
    ->visible(fn (Get $get): bool => $get('type') === 'business'),

Use Set $set inside ->afterStateUpdated() on a ->live() field to mutate another field reactively. Prefer ->live(onBlur: true) on text inputs to avoid per-keystroke updates:

Reactive field update

use Filament\Schemas\Components\Utilities\Set;
use Illuminate\Support\Str;

TextInput::make('title')
    ->required()
    ->live(onBlur: true)
    ->afterStateUpdated(fn (Set $set, ?string $state) => $set(
        'slug',
        Str::slug($state ?? ''),
    )),

TextInput::make('slug')
    ->required(),

Compose layout by nesting Section and Grid. Children span one column by default. Use ->columnSpan() to span multiple columns or ->columnSpanFull() to span the full width:

Section and Grid layout

use Filament\Schemas\Components\Grid;
use Filament\Schemas\Components\Section;

Section::make('Details')
    ->schema([
        Grid::make(2)->schema([
            TextInput::make('first_name'),
            TextInput::make('last_name'),
            TextInput::make('bio')
                ->columnSpanFull(),
        ]),
    ]),

Use Repeater for inline HasMany management. ->relationship() with no args binds to the relationship matching the field name:

Repeater for HasMany

use Filament\Forms\Components\Repeater;

Repeater::make('qualifications')
    ->relationship()
    ->schema([
        TextInput::make('institution')
            ->required(),
        TextInput::make('qualification')
            ->required(),
    ])
    ->columns(2),

Use state() with a Closure to compute derived column values:

Computed table column value

use Filament\Tables\Columns\TextColumn;

TextColumn::make('full_name')
    ->state(fn (User $record): string => "{$record->first_name} {$record->last_name}"),

Use SelectFilter for enum or relationship filters, and Filter with a ->query() closure for custom logic:

Table filters

use Filament\Tables\Filters\Filter;
use Filament\Tables\Filters\SelectFilter;
use Illuminate\Database\Eloquent\Builder;

SelectFilter::make('status')
    ->options(UserStatus::class),

SelectFilter::make('author')
    ->relationship('author', 'name'),

Filter::make('verified')
    ->query(fn (Builder $query) => $query->whereNotNull('email_verified_at')),

Actions are buttons that encapsulate optional modal forms and behavior:

Action with modal form

use Filament\Actions\Action;

Action::make('updateEmail')
    ->schema([
        TextInput::make('email')
            ->email()
            ->required(),
    ])
    ->action(fn (array $data, User $record) => $record->update($data)),

Testing

Testing setup (requires pestphp/pest-plugin-livewire in composer.json):

  • Always call $this->actingAs(User::factory()->create()) before testing panel functionality.
  • For edit pages, pass ['record' => $user->id] and use ->call('save') (not ->call('create')). Edit pages do not redirect after saving by default, so only assert a redirect when one is configured or getRedirectUrl() is overridden.

Table test

use function Pest\Livewire\livewire;

livewire(ListUsers::class)
    ->assertCanSeeTableRecords($users)
    ->searchTable($users->first()->name)
    ->assertCanSeeTableRecords($users->take(1))
    ->assertCanNotSeeTableRecords($users->skip(1));

Create resource test

use function Pest\Laravel\assertDatabaseHas;

livewire(CreateUser::class)
    ->fillForm([
        'name' => 'Test',
        'email' => 'test@example.com',
    ])
    ->call('create')
    ->assertNotified()
    ->assertHasNoFormErrors()
    ->assertRedirect();

assertDatabaseHas(User::class, [
    'name' => 'Test',
    'email' => 'test@example.com',
]);

Edit resource test

livewire(EditUser::class, ['record' => $user->id])
    ->fillForm(['name' => 'Updated'])
    ->call('save')
    ->assertNotified()
    ->assertHasNoFormErrors();

assertDatabaseHas(User::class, [
    'id' => $user->id,
    'name' => 'Updated',
]);

Testing validation

livewire(CreateUser::class)
    ->fillForm([
        'name' => null,
        'email' => 'invalid-email',
    ])
    ->call('create')
    ->assertHasFormErrors([
        'name' => 'required',
        'email' => 'email',
    ])
    ->assertNotNotified();

Use ->callAction(DeleteAction::class) for page actions, or ->callAction(TestAction::make('name')->table($record)) for table actions:

Calling actions

use Filament\Actions\Testing\TestAction;

livewire(ListUsers::class)
    ->callAction(TestAction::make('promote')->table($user), [
        'role' => 'admin',
    ])
    ->assertNotified();

Correct namespaces

  • Form fields (TextInput, Select, Repeater, etc.): Filament\Forms\Components\
  • Infolist entries (TextEntry, IconEntry, etc.): Filament\Infolists\Components\
  • Layout components (Grid, Section, Fieldset, Tabs, Wizard, etc.): Filament\Schemas\Components\
  • Schema utilities (Get, Set, etc.): Filament\Schemas\Components\Utilities\
  • Table columns (TextColumn, IconColumn, etc.): Filament\Tables\Columns\
  • Table filters (SelectFilter, Filter, etc.): Filament\Tables\Filters\
  • Actions (DeleteAction, CreateAction, etc.): Filament\Actions\. Never use Filament\Tables\Actions\, Filament\Forms\Actions\, or any other sub-namespace for actions.
  • Icons: Filament\Support\Icons\Heroicon enum (e.g., Heroicon::PencilSquare)

Common mistakes

  • Never assume public file visibility. File visibility is private by default. Always use ->visibility('public') when public access is needed.
  • Never assume full-width layout. Grid, Section, Fieldset, and Repeater do not span all columns by default.
  • Use Select::make('author_id')->relationship('author', 'name') for BelongsTo fields. BelongsToSelect does not exist; use Select::relationship().
  • Repeater uses ->schema(), not ->fields().
  • Never add ->dehydrated(false) to fields that need to be saved. It strips the value from form state before ->action() or the save handler runs. Only use it for helper/UI-only fields.
  • Use correct property types when overriding Page, Resource, and Widget properties. These properties have union types or modifiers that must be preserved:
    • $navigationIcon: protected static string | BackedEnum | null (not ?string)
    • $navigationGroup: protected static string | UnitEnum | null (not ?string)
    • $view: protected string (not protected static string) on Page and Widget classes

Version History

  • 2e5f32c Current 2026-09-23 05:35

Same Skill Collection

.claude/skills/echo-development/SKILL.md
.claude/skills/laravel-query-builder/SKILL.md
.claude/skills/medialibrary-development/SKILL.md
.claude/skills/socialite-development/SKILL.md
.claude/skills/spatie-javascript/SKILL.md
.claude/skills/spatie-laravel-php/SKILL.md
.claude/skills/spatie-security/SKILL.md
.claude/skills/spatie-version-control/SKILL.md
.claude/skills/testing-best-practices/SKILL.md
.github/skills/custom-fields-development/SKILL.md
.github/skills/flowforge-development/SKILL.md
.claude/skills/agent-browser-relaticle/SKILL.md
.claude/skills/ai-sdk-development/SKILL.md
.claude/skills/business-review/SKILL.md
.claude/skills/cashier-stripe-development/SKILL.md
.claude/skills/configuring-horizon/SKILL.md
.claude/skills/fortify-development/SKILL.md
.claude/skills/infer-conventions/SKILL.md
.claude/skills/laravel-best-practices/SKILL.md
.claude/skills/livewire-development/SKILL.md
.claude/skills/mcp-development/SKILL.md
.claude/skills/passport-development/SKILL.md
.claude/skills/pennant-development/SKILL.md
.claude/skills/pest-testing/SKILL.md
.claude/skills/screenshot-with-callout/SKILL.md
.claude/skills/sluggable-development/SKILL.md
.claude/skills/tailwindcss-development/SKILL.md
.github/skills/livewire-development/SKILL.md
.github/skills/manual-testing/SKILL.md
.github/skills/tailwindcss-development/SKILL.md

Metadata

Files
0
Version
2e5f32c
Hash
229854cd
Indexed
2026-09-23 05:35

Home - Wiki
Copyright © 2011-2026 iteam. Current version is 2.155.2. UTC+08:00, 2026-09-24 01:31
浙ICP备14020137号-1