Form Validation in React JS
Form Validation in React JS is the process of checking user-entered information before accepting or submitting a form. It ensures that required fields are completed, email addresses follow the expected format, passwords meet specified requirements, and other inputs contain valid data. React developers commonly use the useState() Hook, event handlers, conditional rendering, and built-in HTML validation attributes to implement form validation.
Course Link: JustAcademy React JS Training Course
Course Demo: Register for React JS Course Demo
1. Learning Objectives
After studying this topic, you will be able to:
- Understand form validation in React JS.
- Identify different types of form validation.
- Use HTML validation attributes such as
required, minLength, and type="email".
- Validate form fields using JavaScript conditions.
- Display error and success messages dynamically.
- Validate multiple fields using React state.
- Implement password and confirm-password validation.
- Validate forms during typing, on blur, and on submission.
- Understand client-side and server-side validation.
2. What Is Form Validation?
Form validation checks whether the information entered by a user meets the application's requirements. If the information is invalid, the application displays an error message and asks the user to correct it before proceeding.
For example, a registration form may require a name, a valid email address, a phone number, a password, and acceptance of the terms and conditions.
Common Examples of Form Validation
- Name must not be empty.
- Email must follow an acceptable email format.
- Password must meet the application's minimum length and complexity requirements.
- Phone number must follow the expected format.
- Age must be within the permitted range.
- Confirm password must match the password.
- Required checkboxes must be selected.
Form validation improves data quality, user experience, and application reliability. However, client-side validation alone is not sufficient for security.
3. Types of Form Validation
3.1 Client-Side Validation
Client-side validation runs in the user's browser before the data is submitted to the server. React state, JavaScript conditions, and HTML validation attributes can be used for this purpose.
Advantages:
- Provides immediate feedback.
- Reduces unnecessary requests to the server.
- Helps users correct mistakes quickly.
- Improves the overall form experience.
3.2 Server-Side Validation
Server-side validation checks submitted data on the backend before processing or storing it. It is essential because users can bypass browser-based validation.
Examples: Checking whether an email address is already registered, verifying permissions, validating data against database rules, and enforcing business requirements.
3.3 HTML Validation
HTML provides built-in validation attributes that work without writing custom validation logic for every rule.
<input type="text" required />
<input type="email" required />
<input type="password" minLength="8" required />
<input type="number" min="18" max="60" />
3.4 Custom JavaScript Validation
Custom validation uses JavaScript conditions to check requirements that are not adequately covered by built-in HTML attributes.
if (!email.trim()) {
setError("Email is required.");
}
4. Basic Form Validation in React
React can store input values and validation errors in state. When a user submits the form, the application checks the values and displays the appropriate message.
Example: Required Name Validation
import { useState } from "react";
function NameForm() {
const [name, setName] = useState("");
const [error, setError] = useState("");
const [success, setSuccess] = useState(false);
const handleSubmit = (event) => {
event.preventDefault();
if (!name.trim()) {
setError("Name is required.");
setSuccess(false);
return;
}
setError("");
setSuccess(true);
};
return (
<form onSubmit={handleSubmit}>
<label htmlFor="name">Name:</label>
<input
id="name"
type="text"
value={name}
onChange={(event) => {
setName(event.target.value);
setError("");
setSuccess(false);
}}
required
/>
{error && <p role="alert">{error}</p>}
{success && <p role="status">Form submitted successfully!</p>}
<button type="submit">Submit</button>
</form>
);
}
export default NameForm;
Explanation
useState("") creates a state variable for the name.
setName() updates the input value as the user types.
handleSubmit() runs when the form is submitted.
event.preventDefault() prevents the browser's default form submission behavior.
name.trim() checks whether the value contains meaningful text rather than only whitespace.
setError() updates the validation message.
- Conditional rendering displays the error or success message.
5. Built-In HTML Validation Attributes
HTML validation attributes provide simple rules for common form requirements. They can be used directly in React JSX.
| Attribute |
Purpose |
Example |
required |
Requires a value before submission. |
required |
type="email" |
Checks that the entered value follows a browser-recognized email format. |
type="email" |
minLength |
Sets the minimum text length. |
minLength={8} |
maxLength |
Sets the maximum text length. |
maxLength={50} |
min |
Sets the minimum permitted numeric or date value. |
min={18} |
max |
Sets the maximum permitted numeric or date value. |
max={60} |
pattern |
Specifies a regular expression that the value must match. |
pattern="[A-Za-z]+" |
Example
<form>
<label htmlFor="email">Email:</label>
<input
id="email"
type="email"
name="email"
required
/>
<label htmlFor="password">Password:</label>
<input
id="password"
type="password"
name="password"
minLength={8}
required
/>
<button type="submit">Register</button>
</form>
Important: HTML validation can prevent a form's submit event from running when a field is invalid. Custom validation may still be required for rules such as matching passwords or checking whether a username is available.
6. Validating an Email Address
Email validation checks that the user enters an email address in an acceptable format. The type="email" attribute provides basic browser validation, while JavaScript can be used for additional application-specific checks.
Example
import { useState } from "react";
function EmailForm() {
const [email, setEmail] = useState("");
const [error, setError] = useState("");
const handleSubmit = (event) => {
event.preventDefault();
if (!email.trim()) {
setError("Email is required.");
return;
}
if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
setError("Please enter a valid email address.");
return;
}
setError("");
alert("Email validation passed.");
};
return (
<form onSubmit={handleSubmit}>
<label htmlFor="email">Email Address:</label>
<input
id="email"
type="email"
value={email}
onChange={(event) => setEmail(event.target.value)}
required
/>
{error && <p role="alert">{error}</p>}
<button type="submit">Validate Email</button>
</form>
);
}
export default EmailForm;
Note: The regular expression above provides a basic format check, not a complete email verification system. Only an appropriate verification process can establish whether an address exists or belongs to the user.
7. Password Validation in React
Password validation checks whether a password satisfies the application's security requirements. Rules may include minimum length, uppercase and lowercase characters, numbers, or special characters, depending on the application's password policy.
Example: Password Requirements
import { useState } from "react";
function PasswordForm() {
const [password, setPassword] = useState("");
const [error, setError] = useState("");
const handleSubmit = (event) => {
event.preventDefault();
if (password.length < 8) {
setError("Password must contain at least 8 characters.");
return;
}
setError("");
alert("Password validation passed.");
};
return (
<form onSubmit={handleSubmit}>
<label htmlFor="password">Password:</label>
<input
id="password"
type="password"
value={password}
onChange={(event) => setPassword(event.target.value)}
minLength={8}
required
/>
{error && <p role="alert">{error}</p>}
<button type="submit">Submit</button>
</form>
);
}
export default PasswordForm;
Security Best Practice: Password requirements should follow the application's security policy. Do not store passwords in plain text, expose them in logs, or treat client-side validation as proof that a password is secure.
8. Confirm Password Validation
Confirm-password validation checks whether the password and confirmation fields contain the same value. It is commonly used in registration and password-reset forms.
Example
import { useState } from "react";
function ConfirmPasswordForm() {
const [password, setPassword] = useState("");
const [confirmPassword, setConfirmPassword] = useState("");
const [error, setError] = useState("");
const handleSubmit = (event) => {
event.preventDefault();
if (password !== confirmPassword) {
setError("Passwords do not match.");
return;
}
setError("");
alert("Passwords match.");
};
return (
<form onSubmit={handleSubmit}>
<label htmlFor="password">Password:</label>
<input id="password" type="password" value={password}
onChange={(event) => setPassword(event.target.value)} required />
<label htmlFor="confirmPassword">Confirm Password:</label>
<input id="confirmPassword" type="password"
value={confirmPassword}
onChange={(event) => setConfirmPassword(event.target.value)}
required />
{error && <p role="alert">{error}</p>}
<button type="submit">Register</button>
</form>
);
}
export default ConfirmPasswordForm;
The form compares both values before proceeding. A production application should also validate the password on the server and handle it securely.
9. Validating Multiple Fields Using One State Object
When a form contains multiple fields, React can store all values in one object and use a validation function to check each field. This makes the code easier to maintain as the form grows.
Example: Name and Email Validation
import { useState } from "react";
const initialData = { name: "", email: "" };
function RegistrationForm() {
const [formData, setFormData] = useState(initialData);
const [errors, setErrors] = useState({});
const handleChange = (event) => {
const { name, value } = event.target;
setFormData((previousData) => ({
...previousData,
[name]: value
}));
};
const validateForm = () => {
const newErrors = {};
if (!formData.name.trim()) {
newErrors.name = "Name is required.";
}
if (!formData.email.trim()) {
newErrors.email = "Email is required.";
} else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(formData.email)) {
newErrors.email = "Enter a valid email address.";
}
return newErrors;
};
const handleSubmit = (event) => {
event.preventDefault();
const validationErrors = validateForm();
setErrors(validationErrors);
if (Object.keys(validationErrors).length === 0) {
alert("Form submitted successfully!");
}
};
return (
<form onSubmit={handleSubmit}>
<label htmlFor="name">Name:</label>
<input id="name" name="name" value={formData.name}
onChange={handleChange} required />
{errors.name && <p role="alert">{errors.name}</p>}
<label htmlFor="email">Email:</label>
<input id="email" name="email" type="email"
value={formData.email} onChange={handleChange} required />
{errors.email && <p role="alert">{errors.email}</p>}
<button type="submit">Submit</button>
</form>
);
}
export default RegistrationForm;
Explanation
formData stores the current values.
errors stores validation messages for individual fields.
handleChange() updates the field that changed.
validateForm() checks the values and returns an object of errors.
Object.keys(validationErrors).length === 0 checks whether the form has any validation errors.
- The form proceeds only when the custom validation checks pass.
10. Validation on Change, Blur, and Submit
Form validation can be triggered at different times, depending on the user experience you want to provide.
| Validation Type |
When It Runs |
Example Use |
| On Change |
When the input value changes. |
Checking password length while typing. |
| On Blur |
When the user leaves an input field. |
Displaying an email error after the user leaves the email field. |
| On Submit |
When the user submits the form. |
Checking all required fields before registration. |
| Asynchronous Validation |
When validation depends on an asynchronous operation. |
Checking username availability through an API. |
Example: Validation on Blur
import { useState } from "react";
function UsernameField() {
const [username, setUsername] = useState("");
const [error, setError] = useState("");
const handleBlur = () => {
if (username.trim().length < 3) {
setError("Username must contain at least 3 characters.");
} else {
setError("");
}
};
return (
<div>
<label htmlFor="username">Username:</label>
<input
id="username"
value={username}
onChange={(event) => setUsername(event.target.value)}
onBlur={handleBlur}
/>
{error && <p role="alert">{error}</p>}
</div>
);
}
export default UsernameField;
Best Practice: Choose the validation timing that helps users correct errors without displaying unnecessary messages too early.
11. Showing Errors and Highlighting Invalid Fields
React can conditionally render error messages and apply different CSS classes to invalid fields. This helps users identify exactly which values need correction.
Example
<input
className={errors.email ? "input-error" : ""}
aria-invalid={Boolean(errors.email)}
aria-describedby={errors.email ? "email-error" : undefined}
name="email"
value={formData.email}
onChange={handleChange}
/>
{errors.email && (
<p id="email-error" role="alert">{errors.email}</p>
)}
Example CSS
.input-error {
border: 1px solid red;
outline-color: red;
}
The aria-invalid attribute indicates that a field has an error. The aria-describedby attribute connects the input to its error message, helping assistive technologies communicate the problem.
12. Complete Practical Project: Validated Student Registration Form
Create a student registration form with name, email, phone number, password, confirm password, and course selection. Validate the fields before displaying the submitted details.
Complete Code
import { useState } from "react";
const initialData = {
name: "",
email: "",
phone: "",
password: "",
confirmPassword: "",
course: ""
};
function StudentRegistration() {
const [formData, setFormData] = useState(initialData);
const [errors, setErrors] = useState({});
const [submitted, setSubmitted] = useState(false);
const [submittedData, setSubmittedData] = useState(null);
const handleChange = (event) => {
const { name, value } = event.target;
setFormData((previousData) => ({
...previousData,
[name]: value
}));
setSubmitted(false);
};
const validateForm = () => {
const newErrors = {};
if (!formData.name.trim()) {
newErrors.name = "Name is required.";
}
if (!formData.email.trim()) {
newErrors.email = "Email is required.";
} else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(formData.email)) {
newErrors.email = "Enter a valid email address.";
}
if (!formData.phone.trim()) {
newErrors.phone = "Phone number is required.";
} else if (!/^[0-9]{10}$/.test(formData.phone)) {
newErrors.phone = "Enter a 10-digit phone number.";
}
if (formData.password.length < 8) {
newErrors.password = "Password must contain at least 8 characters.";
}
if (formData.password !== formData.confirmPassword) {
newErrors.confirmPassword = "Passwords do not match.";
}
if (!formData.course) {
newErrors.course = "Please select a course.";
}
return newErrors;
};
const handleSubmit = (event) => {
event.preventDefault();
const validationErrors = validateForm();
setErrors(validationErrors);
if (Object.keys(validationErrors).length === 0) {
const { password, confirmPassword, ...safeData } = formData;
setSubmittedData(safeData);
setSubmitted(true);
} else {
setSubmitted(false);
setSubmittedData(null);
}
};
const handleReset = () => {
setFormData(initialData);
setErrors({});
setSubmitted(false);
setSubmittedData(null);
};
return (
<div>
<h2>Student Registration Form</h2>
<form onSubmit={handleSubmit} noValidate>
<label htmlFor="name">Full Name:</label>
<input id="name" name="name" value={formData.name}
onChange={handleChange} aria-invalid={Boolean(errors.name)}
aria-describedby={errors.name ? "name-error" : undefined} />
{errors.name && <p id="name-error" role="alert">{errors.name}</p>}
<label htmlFor="email">Email Address:</label>
<input id="email" name="email" type="email"
value={formData.email} onChange={handleChange}
aria-invalid={Boolean(errors.email)}
aria-describedby={errors.email ? "email-error" : undefined} />
{errors.email && <p id="email-error" role="alert">{errors.email}</p>}
<label htmlFor="phone">Phone Number:</label>
<input id="phone" name="phone" type="tel"
value={formData.phone} onChange={handleChange}
aria-invalid={Boolean(errors.phone)}
aria-describedby={errors.phone ? "phone-error" : undefined} />
{errors.phone && <p id="phone-error" role="alert">{errors.phone}</p>}
<label htmlFor="password">Password:</label>
<input id="password" name="password" type="password"
value={formData.password} onChange={handleChange}
aria-invalid={Boolean(errors.password)} />
{errors.password && <p role="alert">{errors.password}</p>}
<label htmlFor="confirmPassword">Confirm Password:</label>
<input id="confirmPassword" name="confirmPassword"
type="password" value={formData.confirmPassword}
onChange={handleChange}
aria-invalid={Boolean(errors.confirmPassword)} />
{errors.confirmPassword && (
<p role="alert">{errors.confirmPassword}</p>
)}
<label htmlFor="course">Select Course:</label>
<select id="course" name="course" value={formData.course}
onChange={handleChange} aria-invalid={Boolean(errors.course)}>
<option value="">Choose a course</option>
<option value="React JS">React JS</option>
<option value="Flutter">Flutter</option>
<option value="Figma">Figma</option>
</select>
{errors.course && <p role="alert">{errors.course}</p>}
<button type="submit">Register</button>
<button type="button" onClick={handleReset}>Reset</button>
</form>
{submitted && submittedData && (
<div>
<h3>Registration Successful</h3>
<p role="status">Your form passed client-side validation.</p>
<p>Name: {submittedData.name}</p>
<p>Email: {submittedData.email}</p>
<p>Phone: {submittedData.phone}</p>
<p>Course: {submittedData.course}</p>
</div>
)}
</div>
);
}
export default StudentRegistration;
Project Features
- Manages multiple form fields using one state object.
- Validates required information and email format.
- Checks the phone number against a simple 10-digit rule.
- Checks password length and confirm-password matching.
- Displays individual field error messages.
- Uses accessible attributes for error messages.
- Displays submitted details after client-side validation passes.
- Resets form values, errors, and submitted results.
Important: The 10-digit phone rule is only an example and may need adjustment for different countries. This project performs client-side validation only; it does not create an account, verify the user's identity, or save data to a database. In a real application, validate all important data on the server.
13. Common Form Validation Mistakes
| Mistake |
Solution |
| Checking only whether a string is empty |
Use trim() for fields where whitespace-only values should be rejected. |
| Showing errors without identifying the affected field |
Place clear messages beside the corresponding input. |
| Relying only on HTML validation |
Add custom checks for application-specific rules. |
| Relying only on client-side validation |
Validate important data independently on the server. |
| Using overly strict email regular expressions |
Use appropriate basic format checks and verify addresses when necessary. |
| Not validating matching passwords |
Compare the password and confirm-password values before proceeding. |
| Not updating controlled input state |
Provide an onChange handler that synchronously updates the value. |
| Displaying errors without accessible associations |
Use labels, aria-invalid, aria-describedby, and appropriate error announcements. |
| Storing or displaying passwords unnecessarily |
Never include passwords in submitted-result displays, logs, or persistent client storage. |
14. Best Practices for Form Validation
- Choose validation rules that match the application's requirements.
- Use HTML validation attributes for common checks.
- Use React state for dynamic validation and error messages.
- Keep validation logic in reusable functions when forms become complex.
- Validate on change, blur, or submit according to the user experience.
- Show clear, helpful messages that explain how to fix errors.
- Associate labels and error messages with the relevant fields.
- Preserve valid user input when a submission fails.
- Handle server errors and network failures when submitting data to an API.
- Never assume browser-side validation guarantees data security.
- Keep passwords and other sensitive information out of logs and unnecessary displays.
- Consider form libraries such as React Hook Form or Formik when managing complex forms.
15. Form Validation Interview Questions and Answers
Q1. What is form validation in React?
Form validation checks whether user-entered values meet specified rules before the application processes the data.
Q2. What is the difference between client-side and server-side validation?
Client-side validation runs in the browser and provides immediate feedback. Server-side validation runs on the backend and independently checks data before processing or storing it.
Q3. What is the purpose of the required attribute?
The required attribute prevents a form from passing standard browser validation when the field has no acceptable value.
Q4. How do you display validation errors in React?
Store errors in state and conditionally render messages near the corresponding input fields.
Q5. How do you validate an email address?
Use an input with type="email" for basic browser validation and add custom checks if the application requires them.
Q6. How do you validate a password and confirm password?
Compare the two values and display an error when they do not match. Apply the required password policy separately.
Q7. What is the difference between onChange and onBlur validation?
onChange validation runs as the value changes, while onBlur validation runs when the user leaves the field.
Q8. Why is event.preventDefault() used in form validation?
It prevents the browser's default form submission behavior when the application handles the submission through React.
Q9. Can client-side validation guarantee security?
No. Users can bypass browser checks, so the backend must independently validate important data.
Q10. Which React libraries can help with complex form validation?
React Hook Form and Formik are commonly used to manage form state, validation, and submission workflows.
16. Practice Exercises
- Create a form that validates a required name field.
- Build an email field that displays a helpful validation message.
- Validate a password with a minimum length of eight characters.
- Create password and confirm-password fields and check whether they match.
- Build a registration form with name, email, phone number, and course selection.
- Display field-specific error messages using React state.
- Validate a form when the user leaves an input field.
- Add a reset button that clears values and validation errors.
- Display a success message only after all client-side validation checks pass.
- Extend the form to send data to a backend and display server-side validation errors.
17. Quick Revision Checklist
- Understand the purpose of form validation.
- Know the difference between client-side and server-side validation.
- Use HTML attributes such as
required, minLength, and type="email".
- Use
useState() to store form values and errors.
- Write reusable validation functions.
- Validate multiple fields in a single form.
- Handle password and confirm-password matching.
- Display accessible error messages.
- Validate data on the server before processing it.
- Handle successful submissions and failed requests appropriately.
18. Conclusion
Form Validation is an essential React JS concept for creating reliable registration forms, login pages, contact forms, checkout pages, and other interactive applications. By combining HTML validation attributes, React state, custom validation functions, conditional rendering, and server-side checks, developers can provide helpful feedback and improve data quality.
Explore more topics through JustAcademy React JS Training Course or register through Register for React JS Course Demo.
Official React Reference
For more information, refer to the official React documentation: React Input Reference and React Form Reference.