Validating form input is an important step in the process of collecting and handling data from users. By ensuring that the data entered by the user is in the correct format and meets the requirements of the application, we can improve the accuracy and reliability of the data being collected, as well as improve the user experience by providing clear error messages and preventing the submission of invalid data.
In this article, we’ll learn how to validate form input in React using a variety of techniques, including built-in HTML validation, custom validation rules, and third-party libraries.
Using Built-In HTML Validation
HTML provides several built-in validation attributes that can be used to ensure that the data entered by the user is in the correct format and meets certain criteria. These validation attributes include:
required
: specifies that the input field is required and cannot be left blankpattern
: specifies a regular expression that the input must matchmin
andmax
: specify the minimum and maximum values that the input can have (for numeric input types)minlength
andmaxlength
: specify the minimum and maximum length of the input (for text input types)
For example, consider the following form with a required text input and a required number input with a minimum value of 18:
<form>
<label>
Name:
<input type="text" name="name" required />
</label>
<br />
<label>
Age:
<input type="number" name="age" required min="18" />
</label>
<br />
<input type="submit" value="Submit" />
</form>
If the user attempts to submit the form without entering a name or age, or if the age is less than 18, the browser will display an error message and prevent the form from being submitted.
Custom Validation Rules
In addition to the built-in HTML validation attributes, we can also create custom validation rules in React using JavaScript. This can be useful when the built-in validation attributes are not sufficient or when we need to perform more complex validation checks.
For example, consider the following form with a custom validation rule that requires the password to be at least 8 characters long and to contain at least one uppercase letter, one lowercase letter, and one number:
import React, { useState } from 'react';
function FormExample() {
const [formData, setFormData] = useState({
password: '',
});
function handleChange(event) {
const { name, value } = event.target;
setFormData(prevFormData => ({
...prevFormData,
[name]: value,
}));
}
function handleSubmit(event) {
event.preventDefault();
const passwordRegex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[a-zA-Z\d]{8,}$/;
if (!passwordRegex.test(formData.password)) {
alert('Password must be at least 8 characters long and contain at least one uppercase letter, one lowercase letter, and one number.');
return;
}
alert('Form submitted successfully!');
}
return (
<form onSubmit={handleSubmit}>
<label>
Password:
<input
type="password"
name="password"
value={formData.password}
onChange={handleChange}
/>
</label>
<br />
<input type="submit" value="Submit" />
</form>
);
}
In this example, we use a regular expression to test the password against the custom validation rule. If the password does not meet the rule, we display an error message and prevent the form from being submitted. If the password is valid, we allow the form to be submitted and display a success message.
Using Third-Party Libraries
There are also several third-party libraries available for validation in React, such as Formik, React-Form, and React-Validation. These libraries provide a range of features and functionality, including form validation, error handling, and form submission.
For example, consider the following form using the Formik library:
import React from 'react';
import { Formik, Form, Field } from 'formik';
function FormExample() {
return (
<Formik
initialValues={{
password: '',
}}
validate={values => {
const errors = {};
const passwordRegex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[a-zA-Z\d]{8,}$/;
if (!passwordRegex.test(values.password)) {
errors.password = 'Password must be at least 8 characters long and contain at least one uppercase letter, one lowercase letter, and one number.';
}
return errors;
}}
onSubmit={(values, { setSubmitting }) => {
setTimeout(() => {
alert(JSON.stringify(values, null, 2));
setSubmitting(false);
}, 400);
}}
>
{({ isSubmitting }) => (
<Form>
<Field type="password" name="password" />
<br />
<button type="submit" disabled={isSubmitting}>
Submit
</button>
</Form>
)}
</Formik>
);
}
In this example, we use the Formik component to wrap our form and handle the form state and validation. We specify the initial values for the form fields and define a validation function that checks the password against the custom validation rule. When the form is submitted, we handle the submission and display a success message.
There are many other features and options available with these libraries, such as error handling, form submission, and more. It is worth exploring the documentation for these libraries to see how they can be used in your React applications.
Conclusion
In this article, we learned about form validation in React. We covered the built-in HTML validation attributes, custom validation rules using JavaScript, and using third-party libraries for validation. With these techniques, you can easily validate form input in your React applications to ensure the data is accurate and reliable.
Exercises
To review these concepts, we will go through a series of exercises designed to test your understanding and apply what you have learned.
Create a form with three input fields: name, email, and password. Use the required attribute to make the name and email fields required. Use a custom validation function to ensure that the password is at least 8 characters long and contains at least one uppercase letter, one lowercase letter, and one number.
import React from 'react';
function FormExample() {
const handleSubmit = event => {
event.preventDefault();
const form = event.target;
if (form.checkValidity() === false) {
event.stopPropagation();
}
setValidated(true);
};
return (
<form noValidate onSubmit={handleSubmit}>
<div className="form-group">
<label htmlFor="name">Name</label>
<input type="text" className="form-control" id="name" required />
</div>
<div className="form-group">
<label htmlFor="email">Email</label>
<input type="email" className="form-control" id="email" required />
</div>
<div className="form-group">
<label htmlFor="password">Password</label>
<input type="password" className="form-control" id="password" required pattern="^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[a-zA-Z\d]{8,}$" />
</div>
<button type="submit" className="btn btn-primary">
Submit
</button>
</form>
);
}
Create a form with three input fields: name, email, and password. Use the Formik library to handle the form state and validation. Use a custom validation function to ensure that the name is at least 3 characters long and the email is a valid email address. Use the Yup library to validate the password field and ensure that it is at least 8 characters long and contains at least one uppercase letter, one lowercase letter, and one number.
import React from 'react';
import { Formik, Form, Field } from 'formik';
import * as Yup from 'yup';
const validationSchema = Yup.object().shape({
name: Yup.string().min(3, 'Name must be at least 3 characters').required('Name is required'),
email: Yup.string().email('Invalid email address').required('Email is required'),
password: Yup.string().matches(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[a-zA-Z\d]{8,}$/, 'Password must be at least 8 characters long and contain at least one uppercase letter, one lowercase letter, and one number.').required('Password is required'),
});
function FormExample() {
return (
<Formik
initialValues={{
name: '',
email: '',
password: '',
}}
validationSchema={validationSchema}
onSubmit={(values, { setSubmitting }) => {
// submit form data to backend here
}}
>
{({ isSubmitting }) => (
<Form>
<Field type="text" name="name" placeholder="Name" />
<Field type="email" name="email" placeholder="Email" />
<Field type="password" name="password" placeholder="Password" />
<button type="submit" disabled={isSubmitting}>
Submit
</button>
</Form>
)}
</Formik>
);
}
Create a form with three input fields: name, email, and password. Use the Formik library to handle the form state and validation. Use a custom validation function to ensure that the name is at least 3 characters long and the email is a valid email address. Use the Yup library to validate the password field and ensure that it is at least 8 characters long and contains at least one uppercase letter, one lowercase letter, and one number. Display error messages below the input fields when the form is submitted with invalid data.
import React from 'react';
import { Formik, Form, Field, ErrorMessage } from 'formik';
import * as Yup from 'yup';
const validationSchema = Yup.object().shape({
name: Yup.string().min(3, 'Name must be at least 3 characters').required('Name is required'),
email: Yup.string().email('Invalid email address').required('Email is required'),
password: Yup.string().matches(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[a-zA-Z\d]{8,}$/, 'Password must be at least 8 characters long and contain at least one uppercase letter, one lowercase letter, and one number.').required('Password is required'),
});
function FormExample() {
return (
<Formik
initialValues={{
name: '',
email: '',
password: '',
}}
validationSchema={validationSchema}
onSubmit={(values, { setSubmitting }) => {
// submit form data to backend here
}}
>
{({ isSubmitting }) => (
<Form>
<Field type="text" name="name" placeholder="Name" />
<ErrorMessage name="name" component="div" />
<Field type="email" name="email" placeholder="Email" />
<ErrorMessage name="email" component="div" />
<Field type="password" name="password" placeholder="Password" />
<ErrorMessage name="password" component="div" />
<button type="submit" disabled={isSubmitting}>
Submit
</button>
</Form>
)}
</Formik>
);
}
Create a form with three input fields: name, email, and password. Use the Formik library to handle the form state and validation. Use a custom validation function to ensure that the name is at least 3 characters long and the email is a valid email address. Use the Yup library to validate the password field and ensure that it is at least 8 characters long and contains at least one uppercase letter, one lowercase letter, and one number. Display error messages below the input fields when the form is submitted with invalid data. Use the useEffect hook to reset the form when the component unmounts.
import React, { useEffect } from 'react';
import { Formik, Form, Field, ErrorMessage } from 'formik';
import * as Yup from 'yup';
const validationSchema = Yup.object().shape({
name: Yup.string().min(3, 'Name must be at least 3 characters').required('Name is required'),
email: Yup.string().email('Invalid email address').required('Email is required'),
password: Yup.string().matches(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[a-zA-Z\d]{8,}$/, 'Password must be at least 8 characters long and contain at least one uppercase letter, one lowercase letter, and one number.').required('Password is required'),
});
function FormExample() {
useEffect(() => {
return () => {
// reset form when component unmounts
resetForm();
};
}, []);
return (
<Formik
initialValues={{
name: '',
email: '',
password: '',
}}
validationSchema={validationSchema}
onSubmit={(values, { setSubmitting, resetForm }) => {
// submit form data to backend here
}}
>
{({ isSubmitting, resetForm }) => (
<Form>
<Field type="text" name="name" placeholder="Name" />
<ErrorMessage name="name" component="div" />
<Field type="email" name="email" placeholder="Email" />
<ErrorMessage name="email" component="div" />
<Field type="password" name="password" placeholder="Password" />
<ErrorMessage name="password" component="div" />
<button type="submit" disabled={isSubmitting}>
Submit
</button>
</Form>
)}
</Formik>
);
}
Create a form with three input fields: name, email, and password. Use the Formik library to handle the form state and validation. Use a custom validation function to ensure that the name is at least 3 characters long and the email is a valid email address. Use the Yup library to validate the password field and ensure that it is at least 8 characters long and contains at least one uppercase letter, one lowercase letter, and one number. Display error messages below the input fields when the form is submitted with invalid data. Use the useEffect hook to reset the form when the component unmounts. Use the useContext hook to access the global state and update the global state with the form data when the form is successfully submitted.
import React, { useEffect, useContext } from 'react';
import { Formik, Form, Field, ErrorMessage } from 'formik';
import * as Yup from 'yup';
import { GlobalContext } from './GlobalState';
const validationSchema = Yup.object().shape({
name: Yup.string().min(3, 'Name must be at least 3 characters').required('Name is required'),
email: Yup.string().email('Invalid email address').required('Email is required'),
password: Yup.string().matches(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[a-zA-Z\d]{8,}$/, 'Password must be at least 8 characters long and contain at least one uppercase letter, one lowercase letter, and one number.').required('Password is required'),
});
function FormExample() {
const { setFormData } = useContext(GlobalContext);
useEffect(() => {
return () => {
// reset form when component unmounts
resetForm();
};
}, []);
return (
<Formik
initialValues={{
name: '',
email: '',
password: '',
}}
validationSchema={validationSchema}
onSubmit={(values, { setSubmitting, resetForm }) => {
// submit form data to backend here
setFormData(values);
}}
>
{({ isSubmitting, resetForm }) => (
<Form>
<Field type="text" name="name" placeholder="Name" />
<ErrorMessage name="name" component="div" />
<Field type="email" name="email" placeholder="Email" />
<ErrorMessage name="email" component="div" />
<Field type="password" name="password" placeholder="Password" />
<ErrorMessage name="password" component="div" />
<button type="submit" disabled={isSubmitting}>
Submit
</button>
</Form>
)}
</Formik>
);
}