Model Binding
Fill a form with existing values from an Eloquent model or an array with bind().
public function edit(Post $post): Response
{
return Inertia::render('Posts/Edit', [
'form' => PostForm::make()
->route('posts.update', $post)
->bind($post),
]);
}When to use: edit screens. One form class can handle both "create" and "edit".
Examples
Each example is a live form built from the PHP below it. The docs have no database, so the examples bind arrays; an Eloquent model works the same way.
Basic
title and excerpt come from the bound array. author isn't in it, so the field falls back to its default.
use Erag\InertiaForms\Fields\Submit;
use Erag\InertiaForms\Fields\Textarea;
use Erag\InertiaForms\Fields\TextInput;
use Erag\InertiaForms\Form;
class PostForm extends Form
{
public function fields(): array
{
return [
TextInput::make('title')->required(),
Textarea::make('excerpt')->rows(2),
TextInput::make('author')->default('Editorial team'),
Submit::make('Save post'),
];
}
}
PostForm::make()->bind([
'title' => 'Shipping forms from PHP',
'excerpt' => 'One class describes the fields, the rules and the layout.',
]);Nested keys
Dot-notation names read nested values, such as settings stored in a JSON column. billing.email is present but null, so it starts empty instead of using its default.
use Erag\InertiaForms\Fields\Combobox;
use Erag\InertiaForms\Fields\Fieldset;
use Erag\InertiaForms\Fields\Submit;
use Erag\InertiaForms\Fields\TextInput;
use Erag\InertiaForms\Form;
class SettingsForm extends Form
{
public function fields(): array
{
return [
TextInput::make('team_name')->required(),
Fieldset::make('Address')->columns(2)->fields([
TextInput::make('address.street')->columnSpan(2),
TextInput::make('address.city'),
Combobox::make('address.country')->options(['IN' => 'India', 'US' => 'United States']),
]),
TextInput::make('billing.email')->email()->default('billing@example.com'),
Submit::make('Save settings'),
];
}
}
// For example $team->settings, stored as JSON.
SettingsForm::make()->bind([
'team_name' => 'Acme',
'address' => ['street' => '12 MG Road', 'city' => 'Bengaluru', 'country' => 'IN'],
'billing' => ['email' => null],
]);Advanced: enums, dates and edit mode
The bound values are the kind a model with casts returns: a backed enum, Carbon dates, a collection and an integer flag. Each field converts its value for the browser. Because a model is bound, getModel() switches the button to "Save changes".
use Erag\InertiaForms\Fields\CheckboxGroup;
use Erag\InertiaForms\Fields\DatePicker;
use Erag\InertiaForms\Fields\Radio;
use Erag\InertiaForms\Fields\Submit;
use Erag\InertiaForms\Fields\TextInput;
use Erag\InertiaForms\Fields\TimePicker;
use Erag\InertiaForms\Fields\Toggle;
use Erag\InertiaForms\Form;
use Illuminate\Support\Carbon;
enum PostStatus: string
{
case Draft = 'draft';
case Published = 'published';
case Archived = 'archived';
}
class EditPostForm extends Form
{
public function fields(): array
{
$editing = $this->getModel() !== null;
return [
TextInput::make('title')->required(),
Radio::make('status')->options(PostStatus::class)->buttons()->required(),
DatePicker::make('published_at')->withTime(),
TimePicker::make('reminder_at')->label('Daily reminder'),
CheckboxGroup::make('tags')->inline()->options(['laravel', 'inertia', 'vue', 'php']),
Toggle::make('featured'),
Submit::make($editing ? 'Save changes' : 'Create post'),
];
}
}
// The values an Eloquent model with casts would return.
EditPostForm::make()->bind([
'title' => 'Forms without the boilerplate',
'status' => PostStatus::Published,
'published_at' => Carbon::parse('2026-09-27 10:30:00'),
'reminder_at' => Carbon::parse('2026-09-27 08:00:00'),
'tags' => collect(['laravel', 'inertia']),
'featured' => 1,
]);Where initial values come from
For each field, data() picks the first of these that applies:
- The bound model or array, when it has a value for the field name.
- The field's default from
->default(). - The field's empty value (for example
''for text,nullfor a combobox,[]for a checkbox group).
TextInput::make('title')->default('Untitled');
PostForm::make()->data(); // ['title' => 'Untitled']
PostForm::make()->bind(['title' => 'Hi'])->data(); // ['title' => 'Hi']What counts as "has a value"
- Arrays: the key exists (checked with
Arr::has(), dot notation supported). A key set tonullcounts as present, so the default is not used; the field gets its empty value. - Models: the value is not
null, or the first segment of the name is one of the model's attributes. Accessors and loaded relations work throughdata_get().
Nested data
Dot-notation field names read nested values and produce nested form data.
TextInput::make('address.city');
PostForm::make()->bind(['address' => ['city' => 'Delhi']])->data();
// ['address' => ['city' => 'Delhi']]With a model, address.city works with a JSON column cast to an array, or with a loaded address relation.
Value conversion
Bound values are converted to what each control expects:
| Field | Conversion |
|---|---|
| All fields | A backed enum becomes its value. null becomes the empty value. |
| DatePicker | DateTimeInterface (Carbon) becomes Y-m-d, or Y-m-d\TH:i with withTime(). Strings are passed through unchanged. |
| TimePicker | DateTimeInterface becomes H:i, or H:i:s with withSeconds(). |
| Checkbox / Toggle | Truthy becomes the true value, falsy the false value (1 → true). |
Combobox multiple() / CheckboxGroup | Collections and arrays become a plain list. Enum items become their values. |
| FileUpload | Always starts empty. Existing files are never sent to the browser. |
Date columns
Add a date or datetime cast to your model so the value arrives as Carbon and is formatted for the input. A raw string like 2026-09-27 10:30:00 is passed through as-is.
Binding an array
bind() also accepts a plain array. This is handy for settings stored as JSON, or data from an API.
SettingsForm::make()->bind($team->settings);Reading the bound model
Inside your form, $this->getModel() returns whatever was bound. Use it to tweak fields for edit mode:
public function fields(): array
{
$editing = $this->getModel() !== null;
return [
TextInput::make('email')->email()->required()->readonly($editing),
TextInput::make('password')->password()->required()->authorizedUnless($editing),
Submit::make($editing ? 'Save changes' : 'Create account'),
];
}Model binding does not save anything
bind() only sets initial values. Saving is up to you:
public function update(Request $request, Post $post)
{
$post->update(PostForm::make()->bind($post)->validate($request));
return to_route('posts.index');
}