FilamentPHP select field with relation create new record on parent page
Stefan Bogdanescu
Founder & Senior Architect · 2026-06-29
# FilamentPHP: Mastering Nested Select Fields with Dynamic Record Creation
As senior developers working with Laravel and Filament, we frequently encounter scenarios where building complex forms involving nested relationships presents a unique set of challenges. One common requirement is allowing a user to select an item from a parent relationship (e.g., selecting a `Relation`) and simultaneously create a new related record (e.g., creating an `Address`) directly within the same form interface.
Today, we are diving into a specific roadblock encountered when trying to achieve this dynamic creation using Filament's powerful form builders. We will diagnose why you are receiving an error and provide the correct, idiomatic way to implement conditional record creation based on parent selections.
## The Error: Why `createOptionUsing()` Fails
You are attempting to use a highly effective method—`createOptionForm()`—to dynamically populate the options for a nested select field (`relation_address_id`) based on the selection made in another field (`relation_id`).
The error message you received:
```
Select field [data.relation_address_id] must have a [createOptionUsing()] closure set.
```
This error is not necessarily an indication that your logic is flawed, but rather that Filament requires explicit instruction on *how* to generate the options for dynamic creation within a nested context. When dealing with relationships in Filament, especially when options are dependent on other fields, you must explicitly define this dependency using the appropriate closure method.
The core issue lies in how the relationship data is being accessed and structured for the select field to understand that it needs to execute a specific action (creating a new record) upon selection.
## The Correct Implementation Strategy
To successfully create a new related record dynamically, you need to ensure that the options provided to the select field are generated by logic that references all necessary context—in this case, finding the addresses belonging *only* to the selected relation ID.
The solution involves ensuring your `options()` method correctly queries the database based on the value of the parent field (`relation_id`). While `createOptionForm()` is powerful, often a carefully constructed `options()` closure that handles filtering achieves the desired result cleanly.
Let's refactor your form logic to correctly handle the dynamic loading of addresses for a specific relation. We will focus on making the options generation robust and context-aware.
### Refactored Code Example
Here is how you can structure your form to achieve nested creation based on parent selection:
```php
use Filament\Forms;
use App\Models\Relation;
use App\Models\RelationAddress;
public static function form(Form $form): Form
{
return $form
->schema([
// Parent Select Field (The Relation)
Forms\Components\Select::make('relation_id')
->label('Kies een relatie')
->required()
// Ensure this reactive field drives the subsequent options
->reactive(),
// Nested Select Field (The Address)
Forms\Components\Select::make('relation_address_id')
->label('Kies een adres')
// The key is here: dynamically fetch options based on relation_id
->options(function (callable $get) {
$relationId = $get('relation_id');
if (!$relationId) {
return []; // No relation selected, no addresses to show.
}
// Fetch only the addresses related to the selected relation
return RelationAddress::where('relation_id', $relationId)
->pluck('name', 'id');
})
// We use createOptionForm here to signal that selecting an option triggers creation
->createOptionForm([
Forms\Components\TextInput::make('name')
->label('Naam')
->required()
->maxLength(255),
Forms\Components\TextInput::make('postalcode')
->label('Postcode')
->required()
->maxLength(255),
Forms\Components\TextInput::make('housenumber')
->label('Huisnummer')
->required()
->maxLength(255),
Forms\Components\TextInput::make('street')
->label('Straat')
->required()
->maxLength(255),
Forms\Components\TextInput::make('city')
->label('Stad')
->required()
->maxLength(255),
Forms\Components\Select::make('country_id')
->label('Land')
->options(Country::where('enabled', 1)->pluck('name', 'id'))
]),
]);
}
```
## Best Practices and Laravel Context
This pattern relies heavily on the power of Eloquent relationships. Notice how we used `RelationAddress::where('relation_id', $relationId)->pluck(...)`. This demonstrates a fundamental principle in Laravel development: leverage Eloquent’s relationship methods to scope your data queries efficiently before passing them to the form layer. When building complex interfaces, always prioritize fetching the exact data you need on the server side rather than relying solely on client-side filtering.
For more advanced dynamic option generation, especially when dealing with many nested relationships, consider using custom `Select` components or leveraging Filament's ability to hook into model events if standard options methods prove too restrictive. Remember that robust application design, whether in Laravel or any other framework, is built upon clear data flow and explicit handling of database relationships. This principle applies directly to building scalable interfaces on top of your Eloquent models from **[laravelcompany.com](https://laravelcompany.com)**.
## Conclusion
The error you encountered was a signal that the form needed an explicit instruction set for dynamic options, which is perfectly handled by defining a reactive closure within the `options()` method. By correctly scoping your query using the parent field's value (`relation_id`), you successfully bridge the gap between selecting a parent entity and creating its dependent child records seamlessly within Filament. Mastering these nested interactions is key to building powerful, intuitive admin panels with Filament.