Are you exasperated by the chaos of unwieldy form validations in your Next.js projects? 😟 Does managing user input on the server-side feel like an uphill battle fraught with complications? Rest assured, you’re not navigating this labyrinth alone. Countless developers grapple with these exact hurdles while striving to construct reliable web applications.
Enter Zod and Next.js Server Actions—a formidable alliance reshaping the paradigm of form validation within the React ecosystem. 🚀 Envision a landscape where forms are seamlessly validated, errors are gracefully managed, and instantaneous feedback delights your users—all underpinned by the might of server-side processing. This isn’t a lofty aspiration; it’s a tangible reality beckoning for exploration.
In this discourse, we’ll embark on an in-depth exploration of form validation in Next.js, harnessing the prowess of Zod and Server Actions. We’ll commence by unraveling the foundational principles of Next.js Server Actions and illuminating the transformative capabilities of Zod. Subsequently, we’ll escort you through configuring your project, instituting robust validation mechanisms, and enhancing efficiency. By journey’s end, you’ll be equipped with proven methodologies and insights to elevate your form-handling dexterity to unparalleled heights. Let’s delve into this transformative endeavor and pioneer a smoother, more dependable development workflow, fostering applications that users cherish.
Zod is a robust schema declaration and validation library that prioritizes TypeScript. It enables developers to craft intricate schemas for data validation effortlessly. With its intuitive and declarative API, Zod simplifies the process of defining and validating complex data structures, making it a favorite among developers.
Zod stands out as a powerful tool for form validation in Next.js applications due to its numerous advantages:
By leveraging Zod, developers can build reliable, scalable, and user-friendly forms with ease, streamlining the development process while enhancing user experience.
npx create-next-app@latest my-form-app
2.install zod dependency
npm install zod @conform-to/react @conform-to/zod
"use client"; import React, { useActionState } from "react"; import { Caveat } from "next/font/google"; import { reserveCar } from "@/src/utils/action"; import { useForm } from "@conform-to/react"; import { parseWithZod } from "@conform-to/zod"; import { reservationSchema } from "@/src/utils/ReservationSchema"; const caveat = Caveat({ variable: "--font-caveat", subsets: ["latin"], }); const Reservation = () => { const [state, action, isPending] = useActionState(reserveCar, undefined); const [form, fields] = useForm({ onValidate({ formData }) { return parseWithZod(formData, { schema: reservationSchema }); }, shouldValidate: "onBlur", shouldRevalidate: "onInput", }); return ( <div className="w-full p-16 px-16 bg-light rounded-lg shadow-md lg:p-12 md:p-8 sm:px-2 sm:p-2"> <h2 className={`${caveat.variable} text-3xl font-extrabold text-gray-700 mb-6 px-14 sm:px-2`} > Car Reservation </h2> <form id={form.id} onSubmit={form.onSubmit} action={action} className="w-full px-16 sm:px-2" > <div className="grid grid-cols-2 gap-x-6 md:flex md:flex-col"> {/* Name */} <div className="mb-4"> <label htmlFor="name" className="block text-gray-700 font-medium mb-2 uppercase" > FULL Name </label> <input type="text" id="name" className="w-full border border-gray-300 rounded-lg p-2 px-5 py-3 focus:outline-none focus:ring-2 focus:ring-primary" placeholder="Enter your full name" name={fields.name.name} defaultValue={fields.name.initialValue} key={fields.name.key} /> <p className="text-primary text-sm">{fields.name.errors}</p> </div> {/* Phone */} <div className="mb-4"> <label htmlFor="phone" className="block text-gray-700 font-medium mb-2 uppercase" > NUMBER Phone </label> <input type="tel" id="phone" className="w-full border border-gray-300 px-5 py-3 rounded-lg p-2 focus:outline-none focus:ring-2 focus:ring-primary" placeholder="Enter your phone number" /> </div> {/* Address */} <div className="mb-4"> <label htmlFor="address" className="block text-gray-700 font-medium mb-2 uppercase" > Address </label> <input type="text" id="address" name="address" className="w-full border border-gray-300 px-5 py-3 rounded-lg p-2 focus:outline-none focus:ring-2 focus:ring-primary" placeholder="Enter your address" required /> </div> <div className="mb-4"> <label htmlFor="age" className="block text-gray-700 font-medium mb-2 uppercase" > Age </label> <input type="number" id="age" name="age" className="w-full border border-gray-300 px-5 py-3 rounded-lg p-2 focus:outline-none focus:ring-2 focus:ring-primary" placeholder="Enter your age" min={26} required /> </div> {/* Date */} <div className="mb-4"> <label htmlFor="date" className="block text-gray-700 font-medium mb-2 uppercase" > start Reservation Date </label> <input type="date" id="date" name="start_date" className="w-full border border-gray-300 px-5 py-3 rounded-lg p-3 focus:outline-none focus:ring-2 focus:ring-primary" required /> </div> <div className="mb-4"> <label htmlFor="date" className="block text-gray-700 font-medium mb-2 uppercase" > End Reservation Date </label> <input type="date" id="date" name="end_date" className="w-full border border-gray-300 px-5 py-3 rounded-lg p-3 focus:outline-none focus:ring-2 focus:ring-primary" required /> </div> {/* Hour */} <div className="mb-4"> <label htmlFor="hour" className="block text-gray-700 font-medium mb-2 uppercase" > Reservation Hour </label> <input type="time" id="hour" name="hour" className="w-full border border-gray-300 px-5 py-3 rounded-lg p-2 focus:outline-none focus:ring-2 focus:ring-primary" required /> </div> {/* Select a Car */} <div className="mb-4"> <label htmlFor="car" className="block text-gray-700 font-medium mb-2 uppercase" > Select a Car </label> <select id="car" name="type_car" className="w-full border border-gray-300 px-5 py-3 rounded-lg p-2 focus:outline-none focus:ring-2 focus:ring-primary" required > <option disabled selected> Select a car </option> <option value="DACIA SANDERO">DACIA SANDERO</option> <option value="DACIA DUSTER">DACIA DUSTER</option> <option value="RENAULT CLIO">RENAULT CLIO</option> <option value="HYDAI ACCENT">HYDAI ACCENT</option> <option value="PEUGOUT 3008">PEUGOUT 3008</option> <option value="PEUGOUT 308">PEUGOUT 308</option> </select> </div> <div className="mb-4"> <label htmlFor="city" className="block text-gray-700 font-medium mb-2 uppercase" > City </label> <select id="city" name="city" className="w-full border border-gray-300 px-5 py-3 rounded-lg p-2 focus:outline-none focus:ring-2 focus:ring-primary" required > <option disabled selected> Select a city </option> <option value="casablanca">Casablanca</option> <option value="marrakech">Marrakech</option> <option value="rabat">Rabat</option> <option value="benguerir">benguerir</option> <option value="fes">Fes</option> <option value="tangier">Tangier</option> <option value="agadir">Agadir</option> <option value="meknes">Meknes</option> <option value="oujda">Oujda</option> </select> </div> </div> {/* Submit Button */} <div> <button type="submit" className="w-1/2 flex justify-center bg-red-500 text-white font-semibold py-3 px-4 rounded-lg hover:bg-primary focus:outline-none focus:ring-2 focus:ring-primary" > Reserve Now </button> </div> </form> </div> ); }; export default Reservation;
6. install MongoDB and mongoose:
npm i mongodb & npm i mongoose
Server-side form validation with Zod and Next.js Server Actions provides a robust and efficient solution for managing user input. By combining Zod's schema-driven validation with the server-side capabilities of Next.js, developers can build reliable, type-safe forms that ensure data consistency and deliver a smooth user experience. This approach not only enhances application security but also simplifies the development process, allowing for cleaner and more maintainable code.