Learn More

Try out the world’s first micro-repo!

Learn More

React Form Validation with Yup and Formik

React Form Validation with Yup and Formik

In software development, forms offer a way of receiving data from the users before sending information to the server. On this note, the data obtained through these forms must be validated and checked for mistakes that might break the server or cause problems. An instance of this is verifying that a username contains the required characters, or that the password field value and confirm-password field value match.

In this article, we’ll examine how form validation is achieved in a React Application using the Formik and Yup packages. To easily follow this article, fundamental knowledge of React is required. The code for the sample project we’ll be working with in this GitHub repository.

What Are Formik and Yup?

Formik is a React/React Native package used for handling forms; it keeps track of form values, errors, and events, and handles form submissions. Formik eliminates the work involved in setting up a state for form fields, allowing you to focus more on other aspects of development.

Yup is a JavaScript schema builder for validating or parsing values. It allows you to model complex or inter-dependent validations using built-in validators or custom validations using regular expressions.

Yup Schema

The Yup schema allows you to create validation schema/rules that values should follow. You can create a schema by calling Yup.object().shape(). You’ll pass the schema object as a parameter with the schema rules as the value for the field keys. The schema has different datatypes: string, numbers, date, tuple, arrays, objects, booleans, and mixed. The mixed method allows you to create a schema that matches all data types or the ones you configured. Next, you’ll learn about the different validation methods you can apply to schema types.

Formik allows easy integration with Yup for validating form values and ensures that the submitted data is error-free and matches a predetermined schema. The following sections will cover how to use Formik and Yup to validate forms in a simple React Application.

Create a React App

To create a React app, you’ll need to have Node.js installed. On your terminal, run the following command:

npx create-react-app react-formik

Save this code

Once you create the application, update the App.css file with the following styles:

*{
outline: none;
transition: 0.3s ease all;
}

main{
max-width: 1024px;
margin: auto;
}

.App {
background-color: #202020;
padding: 40px;
min-height: 100vh;
}

.App-logo {
pointer-events: none;
margin: 20px;
}

@media (prefers-reduced-motion: no-preference) {
.App-logo {
animation: App-logo-spin infinite 20s linear;
}
}

.App-header {
margin-bottom: 45px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: calc(10px + 2vmin);
color: white;
text-align: center;
}

.App-header img {
width: 150px;
}

.App-link {
color: #61dafb;
}

.styledInput {
margin-bottom: 25px;
}

.styledInput > input {
background: #fefefe;
border: 1px solid #8db2e2;
box-sizing: border-box;
border-radius: 4px;
height: 50px;
min-width: 100%;
max-width: max-content;
padding: 5px 15px;
padding-top: 0.7rem;
font-family: "Gill Sans", "Gill Sans MT", Calibri, "Trebuchet MS", sans-serif;
color: #242235;
font-style: normal;
font-size: 0.87rem;
line-height: 15px;
}

.styledInput > input:focus {
box-shadow: 1px 2px 4px #8db2e2;
}

.styledInput > input::placeholder {
color: #929292;
font-size: 14.4px;
font-family: "Courier New", Courier, monospace;
font-style: normal;
font-weight: 700;
text-transform: capitalize;
}

.helperText {
color: #dc3545;
font-size: 12px;
min-height: 15px;
text-align: left;
}

button {
color: #fff;
background: #2f4858;
border-radius: 4px;
font-family: "PT Sans", sans-serif;
font-weight: 700;
border: none;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
padding: 10px 15px;
font-size: 18px;
height: 50px;
min-width: 100%;
max-width: max-content;
}

button:hover {
box-shadow: 0px 3.5px 5px #e1e5f1a0;
transform: translateY(-0.7px);
}

button:focus:before {
transition: all 0.4s ease-out;
opacity: 0;
width: 40px;
height: 40px;
margin-top: -20px;
margin-left: -20px;
}

button:before {
border-radius: 50%;
background-color: rgba(255, 255, 255, 0.6);
content: "";
position: absolute;
top: 50%;
left: 50%;
width: 0;
height: 0;
}

@keyframes App-logo-spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}

Save this code

Using Formik and Yup to Validate Forms

The App.js file has a simple sign-up form controlled by Formik. For validation, inject the form validation schema created using Yup into the Formik object:

import logo from "./logo.svg";
import { useFormik } from "formik";
import * as Yup from "yup";
import "./App.css";
import StyledInput from "./components/StyledInput";
import { useState } from "react";

function App() {
const [loading, setLoading] = useState(false);
const validateSchema = Yup.object().shape({
firstName: Yup.string().required("This field is required"),
lastName: Yup.string().notRequired(),
email: Yup.string().email("Please enter a valid email").required("This field is required"),
password: Yup.string()
.required("This field is required")
.min(8, "Pasword must be 8 or more characters")
.matches(/(?=.*[a-z])(?=.*[A-Z])\w+/, "Password ahould contain at least one uppercase and lowercase character")
.matches(/\d/, "Password should contain at least one number")
.matches(/[`!@#$%^&*()_+\-=[\]{};':"\\|,.<>/?~]/, "Password should contain at least one special character"),
confirmPassword: Yup.string().when("password", (password, field) => {
if (password) {
return field.required("The passwords do not match").oneOf([Yup.ref("password")], "The passwords do not match");
}
}),
});

const formik = useFormik({
initialValues: {
firstName: "",
lastName: "",
email: "",
password: "",
confirmPassword: "",
},
validationSchema: validateSchema,
onSubmit: (values, { resetForm }) => {
console.log(values);
setLoading(true);
setTimeout(() => {
setLoading(false);
resetForm();
}, 1000 * 2);
},
});

return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<h4>Signup</h4>
</header>

<main>
<form className="spaceY-lg w100-small w50-lg" onSubmit={formik.handleSubmit}>
<StyledInput
label="First Name"
name="firstName"
onChange={formik.handleChange}
value={formik.values.firstName}
type={"text"}
helperText={formik.errors.firstName ? formik.errors.firstName : ""}
/>
<StyledInput
label="Last Name"
type={"text"}
name="lastName"
onChange={formik.handleChange}
value={formik.values.lastName}
helperText={formik.errors.lastName ? formik.errors.lastName : ""}
/>
<StyledInput
label="Email Address"
type={"email"}
name="email"
onChange={formik.handleChange}
value={formik.values.email}
helperText={formik.errors.email ? formik.errors.email : ""}
/>
<StyledInput
label="Password"
type={"password"}
name="password"
onChange={formik.handleChange}
value={formik.values.password}
helperText={formik.errors.password ? formik.errors.password : ""}
/>
<StyledInput
label="Confirm Password"
type={"password"}
name="confirmPassword"
onChange={formik.handleChange}
value={formik.values.confirmPassword}
helperText={formik.errors.confirmPassword ? formik.errors.confirmPassword : ""}
/>

<button disabled={loading} type={"submit"}>
{loading ? "Loading..." : "Sign Up"}
</button>
</form>
</main>
</div>
);
}

export default App;

Save this code

In the code block above, we can see the validation schema for the sign-up form on line 10. This creates a set of rules that each form field will follow.

On line 27, we have the useFormik hook with the initial values for the form state, the validation schema created with Yup and the onSubmit event for the form. Next, we linked the Formik values to the input fields. Using the First Name form field as a reference, we connected the field value from Formik to the value attribute and for the input to create a controlled component. Finally, we passed the handleSubmit function from Formik to the onSubmit event for the form.

Validation Messages

The validation messages are tips that help the user understand which characters are valid for a specific form field. In addition, they serve as a guide for the user in resolving form errors. Validation messages are accessible through Formik errors for each field. We can see this example on line 61. The First Name field validation message can be accessed from formik.errors.firstName.

Built-in Validators

Yup has some built-in validators we can implement on the validation. As seen in the code block above, we used some built-in validators in the validation schema. As discussed in the previous section, there are different datatypes for a Yup Schema. For each data type, there are different validation methods that can be chained to it. An exception is a boolean datatype that can be either true or false.

Custom Validations (RegEx)

We can create our custom validation rules by using the matches() method for string schema. This accepts a regular expression and the validation message as a value:

    password: Yup.string()
.required("This field is required")
.min(8, "Pasword must be 8 or more characters")
.matches(/(?=.*[a-z])(?=.*[A-Z])\w+/, "Password ahould contain at least one uppercase and lowercase character")
.matches(/\d/, "Password should contain at least one number")
.matches(/[`!@#$%^&*()_+\-=[\]{};':"\\|,.<>/?~]/, "Password should contain at least one specia

Save this code

The schema rule above will check if a value is a string and verify that the string value is not empty. Next, it will check to make sure that the minimum length for the string characters is eight. Finally, the following three validation rules for the value are customized using a regular expression:

  • The first expression checks if there is at least one uppercase letter and one lowercase letter in the string.
  • The second expression checks if the value contains at least one number.
  • The last expression checks if the value contains at least one special character.

This validation can be applied in real-life scenarios for creating a strong password, as seen in the code sample in the App.js file:

Validating a Dynamic Form

The Formik package also comes with built-in components that let us control the form state and events. In this section we’ll examine how to create a dynamic form using Formik form components and Yup. First, we’ll set up a form that allows us to create a list of items:

import "./styles.css";
import * as yup from "yup";
import { Field, FieldArray, Form, Formik } from "formik";
import React from "react";

export default function App() {
const [list, setList] = React.useState([]);
const validationSchema = yup.object().shape({
items: yup.array().of(yup.string().required("This value is required"))
});

return (
<div className="App">
<Formik
initialValues={{
items: [""]
}}
validationSchema={validationSchema}
onSubmit={(values, { resetForm }) => {
setList(values.items);

setTimeout(() => {
console.log("clean");
resetForm();
}, 3000);
}}
>
{({ values }) => (
<Form>
{values.items.map((_, index) => (
<React.Fragment key={index}>
<FieldArray
name="items"
render={(helpers) => (
<div>
<Field name={`items.${index}`}>
{({
field, // { name, value, onChange, onBlur }
form: { touched, errors }, // also values, setXXXX, handleXXXX, dirty, isValid, status, etc.
meta
}) => (
<div>
<input
type="text"
placeholder="Enter item..."
{...field}
/>
{meta.touched && meta.error && (
<small className="error">{meta.error}</small>
)}
</div>
)}
</Field>

<div className="row">
<button
disabled={values.items.length === 1}
onClick={() => {
values.items.length > 1 && helpers.remove(index);
}}
type="button"
className="remove"
>
Remove
</button>
{values.items.length === index + 1 && (
<button
type="button"
onClick={() => {
helpers.push("");
}}
className="add"
>
Add New Item
</button>
)}
</div>
</div>
)}
/>
</React.Fragment>
))}
<button type="submit">Submit</button>
</Form>
)}
</Formik>

<div className="list-wrapper">
<ul>
{list.map((val) => (
<li>{val}</li>
))}
</ul>
</div>
</div>
);
}

Save this code

In the code block above, we have the Yup schema, an array type of strings. As we can see from the Yup schema, the array values are required; we cannot have an empty string as an array value.

Next, we imported the Formik component from the Formik package; this wraps the form. Since we’re working with arrays/dynamic form values, we used the FieldArray component, which helps with array manipulations. On line 32, we have the FieldArray, which is used to render each form field and button. The render props from the FieldArray had helper props passed to them. This prop allowed us to mutate the array values, as seen in the "Add New Item" button, where we used the push() method from the helpers to add new values at the end of the array. Also, the "remove" button calls the remove() method on click, with the item's index to remove passed as a parameter:

Finally, to test your dynamic form, you can use the code sample in this codesandbox.

Conclusion

Formik and Yup provide a great way to manage form state and validate values in a form before sending data to the server. They provide a lot of flexibility and ease when creating forms. You can also utilize the Formik form components or the hooks to handle your forms in a React application.

For additional information on how to use Formik, check the official documentation.

Interested in becoming a Pieces Content Partner?

Learn More

Get our latest blog posts and product updates by signing up for our monthly newsletter! 

Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.

Table of Contents

React

Validation

More from Pieces