Sharing a form validation schema between server and client #52652
Replies: 3 comments
-
I have the same problem and I don't wanna make it a client component. |
Beta Was this translation helpful? Give feedback.
-
Checkout this concept, looks nice to me: https://www.arnaudrenaud.com/articles/nextjs-forms-both-sides-validation/ |
Beta Was this translation helpful? Give feedback.
-
After some research and after experimenting with different approaches, I settled with the following which is mostly vanilla Nextjs 15 and React 19 (only adding zod and useForm). In comparison with the solution from @arnaudrenaud, it has similar UX with less third party dependencies. Checkout my repo nextjs-forms-rsa-single-client-server-validation. Improvements are welcome! Full-Stack Form Implementation with Server Actions & ZodThis document outlines our robust, type-safe, and progressively enhanced form implementation using Next.js Server Actions, Zod for validation, and a custom hook for state management. OverviewThis architecture provides a seamless way to handle form submissions with shared validation logic between the client and server. It ensures a great developer experience (DX) and user experience (UX) by centralizing logic and providing instant feedback. The core idea is to define a single Key Features & Benefits
Third-Party LibrariesThis implementation leverages two powerful, industry-standard libraries:
How It Works
Simple Usage ExampleThe example below shows a simplified version of a form component to illustrate how the It demonstrates how to register fields, display validation errors, show the server's response message, and handle the submission state. // Simplified Form Component Example
'use client'
import { useFormServerAction } from '@/app/lib/forms/useFormServerAction'
import { schema } from './schema' // 1. Import your Zod schema
import { submitForm } from './actions' // 2. Import your server action
export function SimplifiedContactForm() {
// 3. Call the hook with the schema and action
const {
register,
formState: { errors },
isPending,
state, // This holds the response from the server action
submit,
} = useFormServerAction(schema, submitForm)
return (
// 4. Attach the submit handler
<form onSubmit={submit} noValidate>
<div>
<label htmlFor="email">Email</label>
{/* 5. Register your input */}
<input id="email" type="email" {...register('email')} />
{/* 6. Display validation errors */}
{errors.email && <p>{errors.email.message}</p>}
</div>
<div>
<label htmlFor="message">Message</label>
<textarea id="message" {...register('message')} />
{errors.message && <p>{errors.message.message}</p>}
</div>
{/* 7. Display the server response message */}
{state && <p>{state.message}</p>}
{/* 8. Use `isPending` to give user feedback */}
<button type="submit" disabled={isPending}>
{isPending ? 'Submitting...' : 'Submit'}
</button>
</form>
)
} Implementation DetailsBelow are the full implementations for the reusable
|
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
I'm currently trying to wrap my head around patterns for validating a form both server-side (in a Server Action) and client-side (either by hand or using something like react-hook-form).
I'd like to only need to define my schema once, using something like zod, and then use it on both ends. Ideally I'd also have a generic form component that handles things like validation and error states on the client, before passing it back to the server.
The pattern I've developed is to have three files that look something like this:
This works, but I'm wondering if there's a cleaner pattern for this.
Beta Was this translation helpful? Give feedback.
All reactions