Form Handling and Validation
Introduction
Form handling and validation are critical aspects of any frontend application. Ensuring that user input is correctly formatted and meets required criteria is essential for both functionality and security. In this project, built with Next.js, TailwindCSS, and TypeScript, we use Zod, a TypeScript-first schema declaration and validation library, to manage form validation effectively.
Why Use Zod?
Zod provides a simple yet powerful way to define schemas for data validation. Unlike other libraries, it has first-class support for TypeScript, making it a great choice for a strongly-typed environment. Here are some of its key features:
- TypeScript Integration: Automatically infer TypeScript types from schemas.
- Composability: Easily combine schemas for complex validation needs.
- Readable Error Messages: Zod provides clear and detailed error messages for invalid inputs.
Setting Up Zod in Your Project
Installation
First, install Zod in your project:
npm install zod
Defining and Using Schemas
Creating a Schema
Define a schema for the data you want to validate. For example, a form with fields for name, email, and password:
import { z } from "zod";
const formSchema = z.object({
name: z.string().min(1, "Name is required"),
email: z.string().email("Invalid email address"),
password: z.string().min(6, "Password must be at least 6 characters long"),
});
Validating Form Data
Basic Validation
To validate data, use the .parse
or .safeParse
methods provided by Zod.
const formData = {
name: "John Doe",
email: "johndoe@example.com",
password: "securepassword",
};
try {
const validatedData = formSchema.parse(formData);
console.log("Valid data:", validatedData);
} catch (e) {
console.error("Validation errors:", e.errors);
}
.safeParse
Using If you prefer a non-throwing validation method, use .safeParse
, which returns a success flag and result or error.
const result = formSchema.safeParse(formData);
if (result.success) {
console.log("Valid data:", result.data);
} else {
console.error("Validation errors:", result.error.errors);
}
Integrating Zod with Forms in Next.js
Example: A Simple Login Form
Use Zod to validate form inputs before submission.
import { useState } from "react";
import { z } from "zod";
const loginSchema = z.object({
email: z.string().email("Invalid email"),
password: z.string().min(6, "Password must be at least 6 characters"),
});
export default function LoginForm() {
const [formData, setFormData] = useState({ email: "", password: "" });
const [errors, setErrors] = useState({ email: "", password: "" });
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const { name, value } = e.target;
setFormData((prev) => ({ ...prev, [name]: value }));
};
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
const result = loginSchema.safeParse(formData);
if (!result.success) {
const errorObj: Record<string, string> = {};
result.error.errors.forEach((error) => {
if (error.path[0]) errorObj[error.path[0] as string] = error.message;
});
setErrors(errorObj);
} else {
console.log("Form submitted successfully:", result.data);
}
};
return (
<form onSubmit={handleSubmit}>
<div>
<label>Email:</label>
<input
type="email"
name="email"
value={formData.email}
onChange={handleChange}
/>
{errors.email && <p>{errors.email}</p>}
</div>
<div>
<label>Password:</label>
<input
type="password"
name="password"
value={formData.password}
onChange={handleChange}
/>
{errors.password && <p>{errors.password}</p>}
</div>
<button type="submit">Login</button>
</form>
);
}
Handling Advanced Scenarios
Nested Objects
Zod supports validation of nested objects:
const nestedSchema = z.object({
user: z.object({
name: z.string(),
age: z.number().min(18, "Must be at least 18 years old"),
}),
});
Arrays
You can also validate arrays:
const arraySchema = z.array(z.string().min(1, "String cannot be empty"));
const result = arraySchema.parse(["item1", "item2"]);
console.log(result); // ["item1", "item2"]
Recommended Tools
- React Hook Form: Integrate Zod with React Hook Form for better form handling.
- Zod Resolver: Use the
@hookform/resolvers/zod
package to easily connect Zod schemas with React Hook Form.
With Zod, you can handle and validate forms in a clean, efficient, and strongly-typed way. By leveraging its TypeScript-first approach, you ensure your forms are robust and maintainable. Happy coding!