Relationship select default value timing unclear in FilamentPHP Panels v3
0 reputation · 23 Nov 2025, 00:25 UTC
0 reputation · 23 Nov 2025, 00:25 UTC
Goal: Determine whether default values are set on a relationship select field before or after the afterStateHydrated callback executes in a Filament form built with Laravel 10+, Livewire v3 and Filament Panels v3.
Constraints: The form uses a BelongsTo relationship select that may be nullable, and the application relies on afterStateHydrated to perform additional UI adjustments based on the loaded value. Version compatibility requires Laravel 10.x, Livewire 3.x and Filament 3.x, but the exact hydration order is not documented and appears to differ from Panels v2 behavior.
Questions:
afterStateHydrated runs?In FilamentPHP Panels v3, default values are applied before the afterStateHydrated callback executes. When a form is initialized, Filament populates the state from the model (if editing) or applies the value defined in the default() method (if creating) before triggering the hydration hooks.
The general flow for a Select component tied to a relationship is as follows:
default() value.afterStateHydrated closure is triggered, receiving the state as it exists after the previous steps.Whether a relationship is nullable or non-null does not alter the order of execution, only the value passed to the callback. If a relationship is nullable and no default is provided, afterStateHydrated will receive null. If a default is provided, that value will be present in the state when the callback runs.
To inspect the intermediate state without modifying the Filament core, use Laravel's logging facility within the callback. This allows you to see exactly what the component holds at the moment of hydration:
Select::make('category_id')
->relationship('category', 'name')
->default(1)
->afterStateHydrated(function ($state) {
\Illuminate\Support\Facades\Log::info('Hydration State: ' . var_export($state, true));
})
Repeater or Wizard, hydration may occur in multiple passes as the parent components initialize.$set within afterStateHydrated to change the value, ensure you are not creating a recursive loop that triggers further hydration events.Diagnostic Detail Needed: Is this component located inside a Repeater or Wizard? If so, the hydration sequence may be deferred or repeated based on the parent's state management.
Use comments to ask for clarification. Post a solution as an answer.
34,775 reputation · 23 Nov 2025, 08:56 UTC
To clarify the timing, in Filament v3, the form state is typically populated from the model (or the default() value for new records) before the afterStateHydrated callback is triggered. This means the callback is intended to act upon the already-resolved state.
When dealing with nullable relationships, it is important to verify if the state is null or simply unset, as this can affect subsequent UI logic. To inspect the intermediate state without modifying core files, you can use Log::info() or dd() within the closure:
Select::make('relationship_id')
->relationship('relationship', 'name')
->afterStateHydrated(function ($state, $set) {
Log::info('Hydrated state: ' . var_export($state, true));
})
Note that if this field is nested within a Repeater or Wizard, the hydration lifecycle may differ, and you should verify if the state is available at the expected moment for those specific components.