Forms are where Inertia.js earns its keep. In a classic SPA you rebuild half of Laravel's validation pipeline in JavaScript; with Inertia the rules stay in Laravel and the React side gets a small, complete toolkit for state, errors and submission. This guide covers the patterns we use in production — from a simple create form to file uploads and dirty-state protection.
- Architecture background: Inertia.js with Laravel and React — SPA without a separate API.
The useForm hook in 20 lines
import { useForm } from '@inertiajs/react';
export default function CreateOrder({ customers }) {
const { data, setData, post, processing, errors } = useForm({
customer_id: '',
note: '',
});
function submit(e) {
e.preventDefault();
post('/orders');
}
return (
<form onSubmit={submit}>
<select value={data.customer_id} onChange={(e) => setData('customer_id', e.target.value)}>
<option value="">Select a customer…</option>
{customers.map((c) => <option key={c.id} value={c.id}>{c.name}</option>)}
</select>
{errors.customer_id && <p className="text-red-500">{errors.customer_id}</p>}
<textarea value={data.note} onChange={(e) => setData('note', e.target.value)} />
{errors.note && <p className="text-red-500">{errors.note}</p>}
<button disabled={processing}>Create order</button>
</form>
);
}
The Laravel side is ordinary validation — no special integration
public function store(StoreOrderRequest $request)
{
Order::create($request->validated());
return redirect()->route('orders.index')->with('success', 'Order created.');
}
When validation fails, Inertia redirects back with errors attached to props; useForm reads them automatically. Every field stays filled — nothing to preserve manually.
What useForm gives you
| Feature | What it does |
|---|---|
data / setData |
Reactive form state, single field or whole object |
errors |
Laravel validation errors, keyed by field |
processing |
True while the request is in flight — disable buttons |
progress |
Upload progress (0–100) for file forms |
isDirty |
Whether anything changed — wire it to a leave warning |
reset() / clearErrors() |
Reset after success, clear on field focus |
transform() |
Reshape the payload before submission |
File uploads
const { data, setData, post, progress } = useForm({ document: null });
post('/contracts', {
forceFormData: true, // multipart even for small payloads
});
Inertia submits uploads as multipart automatically when it detects a File. progress feeds a progress bar; Laravel validates the file exactly as in any Blade form (mimes:pdf, max:10240).
The patterns that prevent bugs
Warning: Never spread
datainto a controlled input you also reset by remounting the component. If the page re-renders with a new key, useForm state is recreated and the user's input disappears — the most common "Inertia ate my form" bug.
- One useForm per form. Multiple hooks on one page invite state drift; extract sections into components that receive
formas a prop instead. - Server decides, client displays. Keep business validation in FormRequests; the React side only renders errors. No duplicated rule sets.
- Disable, do not hide. While
processing, disable the submit button — users who double-click otherwise create two orders. - Dirty-state guard. Combine
isDirtywithuseEffectto warn before navigating away from unsaved changes. - Redirect after success. Return
redirect()from the controller — Inertia follows it as a normal page visit and the form state resets with the page.
Testing form flows
Feature tests exercise the same endpoints the form posts to — validation rules, authorization, redirects. On the frontend, component tests cover rendering of errors and disabled states. Our approach is in Testing Inertia.js applications.
When to reach for a form library
Complex wizards with conditional client-side branching, dynamic field arrays and heavy interdependencies between inputs still benefit from Formik or React Hook Form — with useForm handling the final submission. In our projects that is the exception, not the rule: most CRUD forms are cleaner in plain useForm.
Need forms that hold up under real users?
See Laravel development services.
FAQ
How does Inertia.js handle validation errors?
Laravel throws a ValidationException; Inertia redirects back with errors in props; useForm maps them to fields. No manual wiring.
Do I need Formik or React Hook Form?
Rarely. useForm covers state, errors, processing and uploads. Libraries pay off for client-only complexity like multi-step wizards.
Why does my form lose data on validation failure?
Usually because fields live outside useForm or the component remounts with a new key. Keep all state in useForm — it preserves values by design.
👉 Need robust forms in your Laravel app? Check our Laravel development services or hire a Laravel developer.
📖 Read more: Inertia.js with Laravel and React, Inertia.js v2 features and testing Inertia.js applications.