Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

Joey33's avatar

Joey33 wrote a reply+100 XP

5mos ago

How Do You Handle Client-Side Validation in the New Inertia Form Component

I've been trying to implement tanstack from shadcn but had issues with displaying errors returned from failed validation by laravel so ended up with useForm from Inertia and zod for client-side. Works like a charm. Here you are:

import * as z from 'zod';

rules:

...
const LessonSchema = z.object({
    title: z
        .string()
        .min(5, 'Title must be at least 5 characters.')
        .max(10, 'Title must be at most 32 characters.')
    description: z
        .string()
        .min(20, 'Description must be at least 20 characters.')
        .max(100, 'Description must be at most 100 characters.'),
});

later in the form component closure

form fields

 <div>
                            <label htmlFor="title" className="mb-1 block text-sm font-medium text-gray-700">
                                Title
                            </label>
                            <input
                                type="text"
                                id="title"
                                value={data.title}
                                // Clear client-side error when user starts typing
                                onChange={(e) => {
                                    setData('title', e.target.value);
                                    if (clientErrors.title) {
                                        setClientErrors((prev) => ({ ...prev, title: undefined }));
                                    }
                                }}
                                className={`w-full rounded-lg border p-3 shadow-sm transition duration-150 ${
                                    isError('title')
                                        ? 'border-red-500 focus:ring-red-500'
                                        : 'border-gray-300 focus:ring-green-500'
                                }`}
                                onBlur={() => validateData(data)} // Validate on blur for immediate feedback
                            />
                            {getError('title') && <p className="mt-1 text-sm text-red-600">{getError('title')}</p>}
                        </div>