Forms, data, and validation
Inertify forms are container-resolved PHP classes. They define functional schema, authorization, initial data, validation, and upload behavior; the serialized resource gives Vue the information it needs to manage the form.
Define a form
Return fields and fieldsets from fields(). Fields without an explicit fieldset are grouped automatically.
<?php
namespace App\Forms;
use Inertify\Form\Fields\Fieldset;
use Inertify\Form\Fields\File;
use Inertify\Form\Fields\Submit;
use Inertify\Form\Fields\TextInput;
use Inertify\Form\Form;
final class ProfileForm extends Form
{
protected bool $unsavedWarning = true;
protected bool $scrollToFirstError = true;
public function fields(): array
{
return [
Fieldset::make('Profile')
->id('profile')
->description('Public account details.')
->fields([
TextInput::make('name', 'Name')
->required()
->maxLength(120)
->precognitive(),
TextInput::make('email', 'Email')
->email()
->required()
->precognitive(),
File::make('avatar', 'Avatar')
->image()
->maxSize(5 * 1024),
Submit::make('Save profile'),
]),
];
}
}
Use Laravel validation rules directly with rule() or rules(). Field helpers such as required(), email(), maxLength(), and image() add the corresponding managed rules and serialize useful client metadata.
This example uses the default managed upload strategy for avatar, so register the opt-in upload routes in the host application:
use Illuminate\Support\Facades\Route;
Route::inertiaFormUploads();
Keep the default authentication middleware or replace it with application-specific authorization, tenant, and rate-limit middleware.
Send the resource through Inertia
A form implements ProvidesInertiaProperty, so pass it directly as an Inertia prop. The current request and owning prop key are supplied while it serializes.
use App\Forms\ProfileForm;
use App\Models\Profile;
use Inertia\Inertia;
use Inertia\Response;
public function edit(Profile $profile): Response
{
return Inertia::render('Profiles/Edit', [
'form' => ProfileForm::make()
->bind($profile, except: ['internal_note'])
->route('profiles.update', ['profile' => $profile])
->patch(),
]);
}
bind() accepts an Eloquent model or array. data([...]) overrides bound values, and field defaults fill only missing paths. Nested defaults, including repeater rows, use dotted paths. Mark sensitive or computed fields with withoutModelBinding() when they should never inherit a model value.
Actions may be set with route() or url(). Use get(), post(), put(), patch(), delete(), or method() to choose the HTTP method; a named Laravel route can also supply its method.
Validate the submission
The contextual #[Validate] attribute resolves the typed form, attaches the current request, authorizes it, and validates it before the controller runs.
use App\Forms\ProfileForm;
use App\Models\Profile;
use Illuminate\Http\RedirectResponse;
use Inertify\Form\Validate;
public function update(
Profile $profile,
#[Validate] ProfileForm $form,
): RedirectResponse {
$profile->update($form->validated(files: false));
if ($avatar = $form->upload('avatar')) {
$avatar->store('avatars', 'public');
}
return back()->with('success', 'Profile updated.');
}
validated() retains native files or secure upload tokens. validated(files: false) recursively removes every File value so file storage can be handled separately. Resolve token-based uploads with upload() or uploads(); native storeWithForm() files remain in validated data and Laravel's request file bag.
For explicit control, call setRequest(), validate(), and validated() yourself:
$form = ProfileForm::make()->setRequest($request);
$form->validate();
$data = $form->validated(files: false);
Override messages() and attributes() on the form to customize Laravel validation output. Fields marked precognitive() can be validated individually by the Vue engine with Laravel Precognition; stale client requests are cancelled automatically.
Authorize the resource
Forms, fieldsets, and fields support authorize(), authorizedWhen(), and authorizedUnless().
TextInput::make('internal_note')
->authorize(fn (): bool => auth()->user()->can('editInternalNotes'));
Unauthorized fields are omitted from schema, initial data, and validation rules. An unauthorized form serializes as an empty resource unless inertia-forms.authorization.throw_on_unauthorized is enabled, while validating an unauthorized form always throws an authorization exception.