In Livewire, what is a Form object created with php artisan livewire:form, and how do you bind, validate and reset its fields?
answer
- class extends Livewire\Form
- app/Livewire/Forms by default
- wire:model="form.field"
- errors keyed as form.field
- reset() restores declared defaults
basics
~20 sA Livewire Form object is a class extending Livewire\Form (livewire:form writes it to app/Livewire/Forms) that holds a form's fields, #[Validate] rules and save logic. A component declares public FilterForm $form; inputs bind to form.field, and $this->form->validate() and reset() act on the form.
solid answer
~40 s`php artisan livewire:form ProductFilterForm` creates `app/Livewire/Forms/ProductFilterForm.php`, a class extending `Livewire\Form`. You move the form's public fields, their `#[Validate]` rules and methods such as `store()` or `apply()` into it, and the component declares `public ProductFilterForm $filters;` without instantiating it. Inputs bind with dot notation, `wire:model="filters.minPrice"`, and errors are keyed the same way, `filters.minPrice`. `$this->filters->validate()` validates the form, and the component's own `$this->validate()` includes form objects too. `$this->filters->reset()` restores the defaults declared on the class, `reset('minPrice')` one field, and `pull()` returns values then resets. Form objects keep large components readable and let create and edit screens share one class; computed properties are not supported on them.
code
php · 28 lines<?php
use App\Livewire\Forms\ProductFilterForm;
use Livewire\Component;
new class extends Component {
public ProductFilterForm $filters;
public function apply(): void
{
$this->filters->validate();
// query products with $this->filters->all() ...
}
public function clear(): void
{
$this->filters->reset();
}
};
?>
<form wire:submit="apply">
<input type="text" wire:model="filters.search">
<input type="number" wire:model.live.blur="filters.minPrice">
@error('filters.minPrice') <span>{{ $message }}</span> @enderror
<button type="submit">Apply</button>
<button type="button" wire:click="clear">Clear</button>
</form>go deeper
Recall the livewire:form command, the Livewire\Form base class, and binding with form.field in wire:model.
Explain how validation and error keys work with form objects, what reset() and pull() restore, and why defaults matter.
Design form objects shared by create and edit screens, keep rules with the data they check, and avoid unsupported computed properties.
Decide when form objects are the standard for Livewire forms and how they relate to services and Laravel validation elsewhere.
## Why form objects exist A Livewire component with a big form accumulates many public properties, rules and helper methods next to its real behaviour. A **form object** extracts that form into its own class: fields, validation and persistence logic, reusable by several components. It is a Livewire-specific concept, not a Laravel form request. ## Creating and using one ```bash php artisan livewire:form ProductFilterForm ``` This writes `app/Livewire/Forms/ProductFilterForm.php`: ```php namespace App\Livewire\Forms; use Livewire\Attributes\Validate; use Livewire\Form; class ProductFilterForm extends Form { #[Validate('nullable|string|max:100')] public string $search = ''; #[Validate('nullable|numeric|min:0')] public $minPrice = null; #[Validate('nullable|numeric|gte:minPrice')] public $maxPrice = null; } ``` The component declares a typed public property and lets Livewire create the instance: ```php public ProductFilterForm $filters; ``` ## Binding and errors - Inputs bind with dot notation: `wire:model="filters.search"`, `wire:model.live.blur="filters.minPrice"`. - Validation errors use the same prefix: the error for `minPrice` is keyed `filters.minPrice`. - `#[Validate]` rules on the form run on update exactly as on a component, so real-time validation still works. ## Validating | Call | What it validates | |---|---| | `$this->filters->validate()` | Only the form object's rules | | `$this->filters->validateOnly('minPrice')` | One field of the form | | `$this->validate()` on the component | The component's rules plus its form objects' rules | A form object can also define `rules()` for rule objects built at runtime, just like a component. ## Resetting and reading values - `$this->filters->reset()` restores **every** field to the default declared on the class. - `$this->filters->reset('minPrice', 'maxPrice')` restores only those fields. - A typed field with **no default** becomes uninitialised after `reset()`, so give fields defaults (`public string $search = ''`) if the view reads them right after a reset. - `$this->filters->pull()` returns the values and resets them in one step; `all()` and `only([...])` return values without resetting. - `reset()` restores values; validation messages are separate and are cleared with the reset-validation helpers or by the next successful `validate()`. ## Sharing one form between screens A form object can hold a model and methods for both paths: 1. `setProduct(Product $product)` fills the fields for editing. 2. `store()` validates and creates. 3. `update()` validates and saves the held model. The create and edit components both declare the same form type and call the matching method. ## Form object or plain properties? | Situation | Better choice | |---|---| | Two or three fields used by one component | Plain public properties with `#[Validate]` | | A long form with its own rules and save logic | A form object | | The same fields on create and edit screens | A form object shared by both components | | Several independent forms on one component | One form object per form, e.g. `$filters` and `$savedSearch` | The trade-off is indirection: a small form split into another file is harder to read, while a large one kept inline buries the component's real behaviour. ## Limits - **Computed properties are not supported** on form objects; accessing one through `$form->...` fails. - A form object is state of its component: it is dehydrated with the component's snapshot, so its public fields are user input like any public property. - It is not a Laravel `FormRequest`; it does not authorize requests or resolve from the container per HTTP request.
- In Livewire, what does $this->form->reset() restore a typed field without a default to?Nothing: the field becomes uninitialised, because reset() copies values from a fresh instance of the form class and such a field has no value there. Reading it before assigning throws a typed-property initialisation error, so give form fields explicit defaults.
- Can a Livewire form object hold a #[Computed] property?No. Computed properties are not supported on `Livewire\Form` objects; accessing one via `$form->name` results in an error. Put derived values on the component instead, as a computed property that reads the form's fields.
A form object is like a clipboard a warehouse clerk carries between desks: the fields and checklist travel together, and wiping the clipboard clean (reset) returns every box to its printed default, not to what the last visitor wrote.
saying these in an interview costs you the question
- A Livewire form object is the same thing as a Laravel FormRequest
- You must instantiate the form object yourself in mount()
- Inputs bind to form fields by their bare name, wire:model="minPrice"
- reset() on a form restores the values the form was filled with
- Form objects support #[Computed] like components