DEV Community

Cover image for Advanced Form Handling with Laravel and Inertia.js

Advanced Form Handling with Laravel and Inertia.js

“Controlling complexity is the essence of computer programming.” — Brian Kernighan

Key Takeaways

  • Simplified Development: Inertia.js bridges the Laravel backend with modern frontend frameworks without API complexity
  • Enhanced Performance: Async requests, partial reloads, and optimistic updates create responsive user experiences
  • Robust Validation: Combine server-side Laravel validation with real-time client-side feedback
  • File Upload Excellence: Implement drag-and-drop interfaces with previews and progress tracking
  • Form State Management: Use the useForm hook for consistent, efficient form handling across components
  • Progressive Enhancement: Start simple and add advanced features like multi-step forms and real-time validation as needed

Index

  1. Introduction
  2. Core Form Implementation
  3. Advanced Features
  4. Stats
  5. Best Practices
  6. Interesting Facts
  7. FAQs
  8. Conclusion

1. Introduction

Laravel and Inertia.js create a powerful combination for building modern web applications without the complexity of traditional SPAs. This guide explores advanced form handling techniques that leverage the strengths of both frameworks.

2. Core Form Implementation

Laravel Controller Setup

<?php namespace App\Http\Controllers; use App\Http\Requests\UserRequest; use App\Models\User; use Inertia\Inertia; class UserController extends Controller { public function create() { return Inertia::render('Users/Create'); } public function store(UserRequest $request) { $user = User::create($request->validated()); return redirect() ->route('users.index') ->with('success', 'User created successfully!'); } } 
Enter fullscreen mode Exit fullscreen mode

Form Request Validation

<?php namespace App\Http\Requests; use Illuminate\Foundation\Http\FormRequest; use Illuminate\Validation\Rule; class UserRequest extends FormRequest { public function rules() { return [ 'name' => ['required', 'string', 'max:255'], 'email' => ['required', 'email', Rule::unique('users')], 'avatar' => ['nullable', 'image', 'max:2048'], 'settings' => ['array'], ]; } } 
Enter fullscreen mode Exit fullscreen mode

React Component with useForm

import { useForm } from '@inertiajs/react'; const UserForm = ({ user = null }) => { const { data, setData, post, put, processing, errors } = useForm({ name: user?.name || '', email: user?.email || '', avatar: null, }); const handleSubmit = (e) => { e.preventDefault(); const options = { preserveScroll: true, onSuccess: () => user ? null : reset(), }; user ? put(route('users.update', user.id), options) : post(route('users.store'), options); }; return ( <form onSubmit={handleSubmit}> <input type="text" value={data.name} onChange={e => setData('name', e.target.value)} className={errors.name ? 'border-red-500' : ''} /> {errors.name && <p className="text-red-500">{errors.name}</p>} <button type="submit" disabled={processing}> {processing ? 'Saving...' : 'Save'} </button> </form> ); }; 
Enter fullscreen mode Exit fullscreen mode

3. Advanced Features

File Upload with Preview

const FileUpload = ({ name, onChange, error }) => { const [preview, setPreview] = useState(null); const handleFileSelect = (file) => { if (file && file.type.startsWith('image/')) { const reader = new FileReader(); reader.onload = (e) => setPreview(e.target.result); reader.readAsDataURL(file); } onChange(file); }; return ( <div className="border-2 border-dashed p-4"> <input type="file" accept="image/*" onChange={e => handleFileSelect(e.target.files[0])} /> {preview && ( <img src={preview} alt="Preview" className="mt-2 h-32 w-32 object-cover" /> )} {error && <p className="text-red-500">{error}</p>} </div> ); }; 
Enter fullscreen mode Exit fullscreen mode

Real-time Validation

import { debounce } from 'lodash'; const useRealTimeValidation = () => { const [errors, setErrors] = useState({}); const validateField = useCallback( debounce(async (field, value) => { const response = await fetch('/validate', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ field, value }), }); const result = await response.json(); setErrors(prev => ({ ...prev, [field]: result.error })); }, 500), [] ); return { errors, validateField }; }; 
Enter fullscreen mode Exit fullscreen mode

Optimistic Updates

const useOptimisticForm = (initialData) => { const [optimisticData, setOptimisticData] = useState(null); const form = useForm(initialData); const submitWithOptimisticUpdate = (method, url, optimisticUpdate) => { setOptimisticData(optimisticUpdate); form[method](url, { onSuccess: () => setOptimisticData(null), onError: () => setOptimisticData(null), }); }; return { ...form, optimisticData, submitWithOptimisticUpdate }; }; 
Enter fullscreen mode Exit fullscreen mode

“Leadership is about making others better as a result of your presence — and making sure that impact lasts in your absence.” — Sheryl Sandberg

4. Stats

Inertia.js has gained significant traction in the Laravel community, with over 6,000 GitHub stars and more than 85 contributors. Its Laravel adapter has over 2,000 stars.

The recent release of Inertia 2.0 brought major improvements, including async requests, deferred props, prefetching, and polling capabilities. These features represent a foundational rewrite of the whole request/routing layer to support asynchronous operations. (LogRocket Blog — Inertia.js Adoption Guide)

5. Best Practices

1. Form State Management

  • Use the useForm hook for consistent form handling
  • Implement proper error clearing on field changes
  • Preserve scroll position during form submissions

2. Validation Strategy

  • Combine server-side validation with client-side feedback
  • Use debounced real-time validation for better UX
  • Implement progressive enhancement for form validation

3. Performance Optimization

  • Memoize form components to prevent unnecessary re-renders
  • Use partial reloads for large datasets
  • Implement optimistic updates for better perceived performance

4. Error Handling

  • Provide clear, actionable error messages
  • Focus the first error field on validation failure
  • Use toast notifications for global error states

5. File Upload Best Practices

  • Implement drag-and-drop interfaces
  • Show upload progress and preview capabilities
  • Validate file types and sizes on both client and server

6. Interesting Facts

  • No API Required: Inertia.js eliminates the need to write and maintain a separate API, allowing direct data passing from Laravel controllers to frontend components.
  • Performance Benefits: Applications get a significant performance boost because the backend only sends JSON data needed for components, not full HTML, with JavaScript components cached by browsers and CDNs.
  • Hybrid Architecture: Inertia maintains server-side routing while providing a SPA-like experience, replacing full-page reloads with small fetch requests.
  • Framework Support: Inertia supports multiple frameworks, including Laravel, Rails, Phoenix, Django for backends, and React, Vue, and Svelte for frontends.
  • Recent Evolution: Inertia 2.0 includes async requests, deferred props, prefetching, and polling capabilities, with infinite scrolling planned for version 2.1.

7. FAQs

Q: When should I use Inertia.js over traditional Laravel Blade?
A: Choose Inertia when you need dynamic, interactive interfaces but want to avoid the complexity of building a separate API. It’s perfect for applications requiring SPA-like experiences with Laravel’s backend power.

Q: Can I use Inertia.js with existing Laravel applications?
A: Yes! Inertia can be gradually introduced into existing Laravel applications. You can start with specific pages or features and expand usage over time.

Q: How does form validation work with Inertia.js?
A: Inertia seamlessly integrates with Laravel’s form request validation. Errors are automatically passed to your frontend components as props, making error handling straightforward.

Q: Is Inertia.js suitable for large-scale applications?
A: Absolutely. With features like partial reloads, lazy loading, and optimistic updates, Inertia scales well for complex applications while maintaining developer productivity.

Q: What’s the learning curve for Inertia.js?
A: If you’re already familiar with Laravel and a frontend framework (React, Vue, or Svelte), the learning curve is minimal. The concepts are intuitive and well-documented.

“In the technology industry… you need to be a bit uncomfortable to stay relevant.” — Larry Page

8. Conclusion

Advanced form handling with Laravel and Inertia.js represents a significant evolution in web development, combining the robustness of server-side frameworks with the interactivity of modern frontend libraries. The recent release of Inertia 2.0 has further strengthened this combination with async capabilities and performance improvements.

The techniques covered in this guide — from basic form implementation to advanced features like optimistic updates and real-time validation — demonstrate how developers can create sophisticated, user-friendly applications without the traditional complexity of maintaining separate APIs or managing complex stats across multiple layers.

As the Laravel ecosystem continues to evolve, with tools like Laravel Cloud on the horizon, the combination of Laravel and Inertia.js positions developers to build modern, scalable applications efficiently. Whether you’re creating simple CRUD applications or complex multi-step workflows, this stack provides the tools and patterns needed for success in today’s web development landscape.

About the Author: Kishan works as a web developer at AddWebSolution. Passionate about crafting robust web solutions. He works with Laravel, PHP, MySQL, Vue.js, React.js, and more — blending logic and creativity to turn ideas into intuitive digital experiences.

Top comments (0)