javascriptroom blog

Quiz about Forms and Validation in Next.js

Forms are an essential part of web applications, allowing users to input data. In Next.js, handling forms and validating the input is crucial for creating a smooth user experience. This blog will present a quiz - like exploration of forms and validation in Next.js, covering key concepts, common practices, and best practices.

2026-07

Table of Content#

  1. Basic Form Handling in Next.js
  2. Client - Side Validation
  3. Server - Side Validation
  4. Using Third - Party Libraries for Validation
  5. Best Practices

1. Basic Form Handling in Next.js#

In Next.js, you can handle forms using the built - in useState hook (for simple forms) or more advanced libraries.

Example#

import React, { useState } from'react';
 
const MyForm = () => {
    const [name, setName] = useState('');
    const [email, setEmail] = useState('');
 
    const handleSubmit = (e) => {
        e.preventDefault();
        // Here you can send the data to an API or perform other actions
        console.log({ name, email });
    };
 
    return (
        <form onSubmit={handleSubmit}>
            <input
                type="text"
                placeholder="Name"
                value={name}
                onChange={(e) => setName(e.target.value)}
            />
            <input
                type="email"
                placeholder="Email"
                value={email}
                onChange={(e) => setEmail(e.target.value)}
            />
            <button type="submit">Submit</button>
        </form>
    );
};
 
export default MyForm;

2. Client - Side Validation#

Client - side validation is used to provide immediate feedback to the user.

Common Practices#

  • Using HTML5 Validation Attributes: For example, required for required fields, pattern for regex - based validation.
<input
    type="email"
    placeholder="Email"
    value={email}
    onChange={(e) => setEmail(e.target.value)}
    required
    pattern="[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}"
/>
  • Using JavaScript for Custom Validation: You can write custom functions to validate more complex scenarios.
const validateForm = () => {
    let isValid = true;
    if (name === '') {
        isValid = false;
        // You can show an error message here
    }
    if (!email.match(/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/)) {
        isValid = false;
    }
    return isValid;
};
 
const handleSubmit = (e) => {
    e.preventDefault();
    if (validateForm()) {
        // Proceed with form submission
    }
};

3. Server - Side Validation#

Server - side validation is crucial as client - side validation can be bypassed. In Next.js, you can use API routes for server - side validation.

Example#

Create an API route (pages/api/submit-form.js):

export default function handler(req, res) {
    const { name, email } = req.body;
    let errors = {};
    if (!name) {
        errors.name = 'Name is required';
    }
    if (!email.match(/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/)) {
        errors.email = 'Invalid email';
    }
    if (Object.keys(errors).length > 0) {
        res.status(400).json({ errors });
    } else {
        // Here you can save the data to a database etc.
        res.status(200).json({ message: 'Form submitted successfully' });
    }
}

And in the form component:

import React, { useState } from'react';
import axios from 'axios';
 
const MyForm = () => {
    const [name, setName] = useState('');
    const [email, setEmail] = useState('');
    const [errors, setErrors] = useState({});
 
    const handleSubmit = async (e) => {
        e.preventDefault();
        try {
            const response = await axios.post('/api/submit-form', { name, email });
            console.log(response.data);
        } catch (error) {
            if (error.response) {
                setErrors(error.response.data.errors);
            }
        }
    };
 
    return (
        <form onSubmit={handleSubmit}>
            <input
                type="text"
                placeholder="Name"
                value={name}
                onChange={(e) => setName(e.target.value)}
            />
            {errors.name && <p>{errors.name}</p>}
            <input
                type="email"
                placeholder="Email"
                value={email}
                onChange={(e) => setEmail(e.target.value)}
            />
            {errors.email && <p>{errors.email}</p>}
            <button type="submit">Submit</button>
        </form>
    );
};
 
export default MyForm;

4. Using Third - Party Libraries for Validation#

Yup#

Yup is a popular validation library.

Example#

Install Yup: npm install yup

import React, { useState } from'react';
import * as Yup from 'yup';
import axios from 'axios';
 
const schema = Yup.object().shape({
    name: Yup.string().required('Name is required'),
    email: Yup.string().email('Invalid email').required('Email is required')
});
 
const MyForm = () => {
    const [name, setName] = useState('');
    const [email, setEmail] = useState('');
    const [errors, setErrors] = useState({});
 
    const handleSubmit = async (e) => {
        e.preventDefault();
        try {
            await schema.validate({ name, email });
            const response = await axios.post('/api/submit - form', { name, email });
            console.log(response.data);
        } catch (error) {
            if (error.inner) {
                const validationErrors = {};
                error.inner.forEach((err) => {
                    validationErrors[err.path] = err.message;
                });
                setErrors(validationErrors);
            }
        }
    };
 
    return (
        <form onSubmit={handleSubmit}>
            <input
                type="text"
                placeholder="Name"
                value={name}
                onChange={(e) => setName(e.target.value)}
            />
            {errors.name && <p>{errors.name}</p>}
            <input
                type="email"
                placeholder="Email"
                value={email}
                onChange={(e) => setEmail(e.target.value)}
            />
            {errors.email && <p>{errors.email}</p>}
            <button type="submit">Submit</button>
        </form>
    );
};
 
export default MyForm;

5. Best Practices#

  • Separate Concerns: Keep form handling, validation (client and server - side), and UI components separate as much as possible.
  • Provide Clear Error Messages: Make sure error messages are user - friendly and easy to understand.
  • Use Loading States: When submitting forms (especially when making API calls), show a loading state to the user.
const [isLoading, setIsLoading] = useState(false);
 
const handleSubmit = async (e) => {
    e.preventDefault();
    setIsLoading(true);
    try {
        // Form submission logic
    } catch (error) {
        // Error handling
    } finally {
        setIsLoading(false);
    }
};
 
return (
    <form onSubmit={handleSubmit}>
        {/* Form elements */}
        {isLoading && <p>Submitting...</p>}
        <button type="submit" disabled={isLoading}>Submit</button>
    </form>
);

Reference#