Streamlining Laravel Admin Forms with FilamentPHP’s Reusable Components
Learn how to cut duplication in your Filament admin panels by creating reusable form components. A step‑by‑step guide, example, and trade‑offs for efficient, maintainable code.
21 Sept 2026, 12:14 UTC

Concrete Problem: Repeated Form Fields Across Resources
In a typical Laravel admin panel built with FilamentPHP, you often create several resources—Users, Posts, Orders—each with forms that share common fields. For example, many resources need a title, description, or a set of address fields. Copy‑pasting the same field definitions into every resource leads to:
- Code duplication that is hard to maintain.
- Inconsistent UI when a change is made in one place but not another.
- Increased risk of bugs when validation rules diverge.
Filament’s reusable form components solve this by letting you define a field group once and inject it wherever needed.
Thesis: One Definition, Many Resources
By creating a dedicated component class that extends Filament\Forms\Components\Component, you can encapsulate a set of fields, validation, and even custom logic. The component can then be registered in any resource’s form builder with a single line of code, ensuring consistent behavior and simplifying unit testing.
1. Defining a Reusable Component
Components live in app/Filament/Forms/Components by convention. Below is a minimal example that bundles address fields.
label('Street')
->required(),
TextInput::make('city')
->label('City')
->required(),
TextInput::make('zip')
->label('ZIP Code')
->numeric()
->required(),
];
}
}
Key points:
- Extend
Componentto inherit Filament’s form lifecycle. - Return an array of field definitions in
form(). - Use Livewire’s reactivity by adding
->reactive()if needed.
2. Registering the Component in a Resource
In any resource, you can now inject the component via the form() builder:
schema([
// Other fields specific to Order
AddressComponent::make(),
]);
}
}
Remember to run php artisan serve (or your preferred server) after adding the component. Navigate to the admin panel, open the Order form, and you should see the address fields rendered. Validation will automatically apply because the component’s form() method defines the rules.
3. Reusing Across Multiple Resources
Because the component is a class, you can import it wherever needed. For instance, in a UserResource:
schema([
TextInput::make('name')
->required(),
AddressComponent::make(),
]);
}
Both resources now share the exact same address fields, validation, and UI. Updating the component (e.g., adding a state field) automatically propagates to all resources that include it.
4. Trade‑Offs and Limitations
- Version Compatibility: Reusable components rely on Livewire 3 and Filament 3.x. They are not available in older Laravel 8 or Livewire 2 setups.
- Performance: Each component renders a full Livewire component tree. If you embed dozens of complex components in a single form, you may notice increased request time and memory usage.
- Testing Overhead: While components simplify unit tests, you still need to test each component in isolation and ensure it behaves correctly when nested inside a resource.
- Dynamic Data: If a component requires dynamic data (e.g., a list of countries), pass it via constructor or
->statePath()and handle it carefully to avoid stale data.
Practical Verification Checklist
- Create the component class as shown.
- Register it in at least two resources.
- Run
php artisan serveand open each form. - Verify that the fields render identically and that validation triggers on submit.
- Use
php artisan tinkerto inspect the component’sform()output if needed. - Optional: write a unit test for
AddressComponentthat asserts the presence of thestreetfield and its required rule.
Actionable Closing
Reusable form components in FilamentPHP are a powerful way to keep your admin panels DRY and maintainable. Start by identifying the most common field groups across your resources, encapsulate them into component classes, and register them with ->components(). Keep an eye on version compatibility and performance, especially if you plan to embed many components in a single form. With this pattern, future schema changes become a single edit, and your codebase stays clean and testable.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.