In ReactJS, if you have a form in your application and you want to apply validations to the form fields, then you should try the yup package to handle all the validations without worrying about having null checks, empty checks, or regular expressions for validating the user input.
Yup can be used to define a schema, against which the form object can be validated to implement form field validation. Generally, Yup is used along with the Formik package, but you can use it without Formik too. So in this tutorial, we will see a simple code example where we will create a form in ReactJS and validate it using Yup.
Installing Yup
To install yup package, you can use npm in your project folder.
npm install yup
This will install the yup package, which you can use in your project.
Using Yup for Form Validation
Now let's see how you can use yup to set up the schema and validate the form inputs.
Let's create a basic form first.
<form onSubmit={handleForm}>
<div>
<input type="text" placeholder="Your email" name="email"/>
</div>
<div>
<input type="password" placeholder="Enter Password" name="password"/>
</div>
<div>
<input type="radio" placeholder="Add name..." name="gender" value="male"/> Male
<input type="radio" placeholder="Add name..." name="gender" value="female"/> Female
</div>
<div>
<button type="submit">Save</button>
</div>
</form>
In the above form, we have set an event handler for the form submit event. The function handleForm
will be handling the form submission. Before, seeing the implementation of the handleForm
function, let's see how we can start using yup package for the above form field's validation.
1. Import the `yup` package
First things first, let's import the yup package to use it.
import * as yup from 'yup';
2. Define the schema for Form Field validation
Next, you should define the shape of the object using `yup`, the object against which the form object will be matched. Yes, the form on submission is handled as an object where keys are the names of the input fields of the form, and values are the values submitted by the user.
In `yup`, we use the yup.object().shape()
method to define the shape of the object.
const schema = yup.object().shape({
email: yup.string().email().required(),
password: yup.string().required(),
gender: yup.string().required()
})
In the code above, email, password, and gender are the form fields. Then we used the yup methods like string()
, required()
, etc. chaining them to implement the validations.
There are many methods for adding validations email()
for validating email addresses, then min()
to define a minimum length check, then max()
to add a maximum length check, etc.
Yup will return standard error messages for the validations above, but you can provide custom error messages too, as arguments to the validation methods, for example,
const schema = yup.object().shape({
email: yup.string().email("Provide a valid Email address...").required("Email is required..."),
password: yup.string().required("Password is required..."),
gender: yup.string().required("Gender is required...")
})
3. Check if Form Values are Valid
You can check if the form fields that are submitted are valid or not. If not valid, then you can run validation and find the exact errors and then do the needful.
let validForm = await schema.isValid(formObj)
if(validForm) {
// submit the form
}
else {
// check for errors
}
In the code above, formObj
is the form object created from the form fields once the form is submitted. Also, as you can see we have used the await
keyword with the isValid()
method, so the function inside which you call this should be async, using the async
keyword. You can also use the then()
method to handle the Promise returned by the isValid()
method.
4. Validation and getting Error Messages
Once you have checked for the form's validity using the isValid()
method, then you can use the validate()
method to look for the errors. This method should be called in a try...catch
block to catch the error it will throw when the validation fails.
await schema.validate(formObj)
The above code will check the validations on form fields, but it will stop the moment it finds one failed validation. To stop this behavior and check for all the field validations, you should use the abortEarly
flag and set it to false
, like this,
await schema.validate(formObj, { abortEarly: false })
5. HandleForm function
Now let's see the complete implementation of the handleForm
function. We have used the FormData
to handle the form, you can do it in a different style, the idea is to get the form field values in object form, with the same key names as defined in the yup schema.
async function handleForm(e) {
e.preventDefault()
let form = e.target;
let formData = new FormData(form)
let formObj = Object.fromEntries(formData.entries())
try {
let validForm = await schema.isValid(formObj)
if(validForm) {
// submit the form
}
else {
await schema.validate(formObj, { abortEarly: false })
}
}
catch(err) {
console.log(err)
console.log(err.errors)
}
}
So that is how you will handle the form using yup. Now, another very important aspect of form validation is to show the error messages on the user interface.
6. Show Error messages on the UI
The error messages are available in an array format inside the err.errors
field of the err
object that is thrown by the validate()
method.
To show errors on the UI, we should use a state variable, set the errors in that state variable, and use it in the JSX to display messages. Here is the complete working code for you.
import React, { useState } from 'react'
import "./App.css";
import * as yup from 'yup';
const schema = yup.object().shape({
email: yup.string().email("Email is invalid...").required("Email is required..."),
password: yup.string().required("Password is required..."),
gender: yup.string().required("Gender is required...")
})
const Register = () => {
const [error, setError] = useState([])
async function handleForm(e) {
e.preventDefault()
let form = e.target;
let formData = new FormData(form)
let formObj = Object.fromEntries(formData.entries())
try {
let validForm = await schema.isValid(formObj)
if(validForm) {
// submit the form
}
else {
await schema.validate(formObj, { abortEarly: false })
}
}
catch(err) {
setError(err.errors)
// console.log(err)
// console.log(err.errors)
}
}
return (
<>
<div className='card'>
<form onSubmit={handleForm}>
<div>
<input type="text" placeholder="Your email" name="email"/>
{error?.[0] && <div className='error'>{error?.[0]}</div> }
</div>
<div>
<input type="password" placeholder="Enter Password" name="password"/>
{error?.[1] && <div className='error'>{error?.[1]}</div> }
</div>
<div>
<input type="radio" placeholder="Add name..." name="gender" value="male"/> Male
<input type="radio" placeholder="Add name..." name="gender" value="female"/> Female
{error?.[2] && <div className='error'>{error?.[2]}</div> }
</div>
<div>
<button type="submit">Save</button>
</div>
</form>
</div>
</>
)
};
export default Register;
Create a Register component in your ReactJS project and use this code.
Conclusion
You can use yup package without formik in ReactJS but that would require some extra efforts like exploring the error object returned by yup's validate()
method, then writing code to show messages on the user interface, etc. On the other hand, when you use it with Formik, formik takes care of all these things.