React form state management and validation using Formik and Yup
by Tifani Dermendzhieva
In the world of web development, creating forms is one of the most common tasks. Yet, building forms in React applications can become quite challenging, especially when it comes to managing large forms with multiple fields and validating user input. Thankfully, libraries like Formik and Yup come to the rescue, making this process much simpler and more efficient.
In this tutorial, we will explore how you can effortlessly handle form state and input validation using Formik and Yup.
Prerequisites: Setting Up Your React Application
Install NodeJS and NPM
Before we dive into the code, ensure that you have installed:
Create your React app
If you do not have a React application already, let's start with creating one using Create React App. To do so, open your terminal and run the following commands:
mkdir my-formik-yup-app
cd my-formik-yup-app
npx create-react-app my-formik-yup-app .
Install formik and yup
Having created the app, the next step is installing the required libraries - i.e. Formik and Yup:
npm install formik yup
Starting Your App Locally
To start your app locally, run the following command in your terminal:
npm start
If everything is set up correctly, you should be able to see the default react app page by opening your browser and navigating to http://localhost:3000.
Creating a Form Component
Now that we have the React app running, let's focus on creating the form. For our example, let's start with a simple user registration form with fields for username, email, and password.
Creating a simple component (for beginners)
Inside the src/
folder of your React app, create a new file called RegistrationForm.jsx
and add the following code:
import React from "react";
const RegistrationForm = () => {
return <h1>Registration Form </h1>;
};
export default RegistrationForm;
To display the RegistrationForm
component on the main page of the app, remove all unnecessary components from App.js
and add the RegistrationForm
instead:
import "./App.css";
import RegistrationForm from "./RegistrationForm";
function App() {
return (
<div className="App">
<RegistrationForm />
</div>
);
}
export default App;
With this you should be able to see the heading "Registration Form" on your main page.
Creating the registration form in RegistrationForm.jsx
Step 1: Create the form skeleton
import React from "react";
const RegistrationForm = () => {
return (
<div>
<h1>Simple Registration Form</h1>
<form>
<div>
<label htmlFor="username">Username</label>
<input type="text" id="username" name="username" />
</div>
<div>
<label htmlFor="email">Email</label>
<input type="email" id="email" name="email" />
</div>
<div>
<label htmlFor="password">Password</label>
<input type="password" id="password" name="password" />
</div>
<button type="submit">Submit</button>
</form>
</div>
);
};
export default RegistrationForm;
Step 2: Apply styles (optional)
If you want to style up this form a little bit, you can create a style.css
file in the same directory and add your styles. Here is some basic form style that I used for this example.
/* ./style.css */
.label {
text-align: left;
font-weight: 500;
font-size: x-small;
color: rgb(115, 115, 115);
}
.text-field {
width: 100%;
height: 33px;
margin: auto;
background-color: #fff;
border-radius: 10px;
border: 2px solid rgb(202, 202, 202);
}
.text-field:focus {
border: 2px solid #fe8923;
}
.input-container {
display: flex;
flex-direction: column;
justify-content: center;
align-items: self-start;
width: 70%;
}
.form-container {
display: flex;
flex-direction: column;
justify-items: center;
align-items: center;
gap: 15px;
}
.form-card {
width: 720px;
margin: 100px auto;
padding-top: 10px;
padding-bottom: 30px;
box-shadow: rgba(0, 0, 0, 0.24) 0px 3px 8px;
border: 1px solid transparent;
border-radius: 20px;
background-color: #f2fbff;
}
.button {
width: 180px;
background-color: #fe8923;
color: #fff;
box-shadow: rgba(0, 0, 0, 0.24) 0px 3px 8px;
border: 2px solid #fe8923;
border-radius: 10px;
padding: 10px;
margin: 30px 0 0 0;
font-weight: 600;
}
.button:hover {
background-color: #fff;
color: #fe8923;
cursor: pointer;
}
Now you have to apply the class names to the elements you would like to style.
import React from "react";
import "./style.css";
const RegistrationForm = () => {
return (
<div className="form-card">
<h1>Simple Registration Form</h1>
<form>
<div className="form-container">
<div className="input-container">
<label htmlFor="username" className="label">
Username
</label>
<input
type="text"
id="username"
name="username"
className="text-field"
/>
</div>
<div className="input-container">
<label htmlFor="email">Email</label>
<input
type="email"
id="email"
name="email"
className="text-field"
/>
</div>
<div className="input-container">
<label htmlFor="password" className="label">
Password
</label>
<input
type="password"
id="password"
name="password"
className="text-field"
/>
</div>
</div>
<button type="submit" className="button">
Submit
</button>
</form>
</div>
);
};
export default RegistrationForm;
With this our form skeleton is ready. Let's make it functional in the next steps.
Step 3: Use Formik for state management
Firstly, import the formik components for building form elements - Form
, Field
and the form wrapper - Formik
and replace the <form>
and <input>
elements with them.
Secondly, define the initial values for your form fields and pass them to Formik with the initialValues
prop.
Last but not least, define your submit handler and pass it to Formik with the onSubmit
prop.
import React from "react";
import "./style.css";
import { Formik, Form, Field } from "formik";
const RegistrationForm = () => {
const initialFormValues = { username: "", email: "", password: "" };
const submitHandler = (values) => {
console.log(values);
// Handle form submission logic
};
return (
<div className="form-card">
<h1>Simple Registration Form</h1>
<Formik
initialValues={initialFormValues}
onSubmit={(v) => submitHandler(v)}
>
<Form>
<div className="form-container">
<div className="input-container">
<label htmlFor="username" className="label">
Username
</label>
<Field
type="text"
id="username"
name="username"
className="text-field"
/>
</div>
<div className="input-container">
<label htmlFor="email" className="label">
Email
</label>
<Field
type="email"
id="email"
name="email"
className="text-field"
/>
</div>
<div className="input-container">
<label htmlFor="password" className="label">
Password
</label>
<Field
type="password"
id="password"
name="password"
className="text-field"
/>
</div>
</div>
<button type="submit" className="button">
Submit
</button>
</Form>
</Formik>
</div>
);
};
export default RegistrationForm;
Great, you should be able to edit your input values and see them in the browser console when you click on the submit button.
Step 4: Add validation with Yup
Validation with yup is a very easy and straightforward process.
First, you have to define the validation schema you want to apply to the form. In our example we call the schema registrationValidationSchema
and it has three required fields - username, email and password.
You can check out all the methods you can apply to string values in the Yup docs. We will only use required
(to validate presence), email
(to validate email format), and min
(to validate minimum characters count). As argument to each of those methods, you can pass the message that will be displayed to the user when the user input is invalid.
Once your schema is defined, you can apply it to the form by passing it as a prop - validationSchema
, to the Formik
component.
Lastly, to display the validation message to the user, use the ErrorMessage
component from formik
for each input field. It is important to pass the name
prop to ErrorMessage
in order to display the error for the correct field.
import React from 'react';
import "./style.css";
import { Formik, Form, Field, ErrorMessage } from 'formik';
import * as Yup from 'yup';
const RegistrationForm = () => {
const initialFormValues = { username: "", email: "", password: "" };
const registrationValidationSchema = Yup.object({
username: Yup.string().required("Username is required"), // the message shown when the field is empty
email: Yup.string()
.email("Invalid email address") // the message shown when the email input has invalid format
.required("Email is required"), // the message shown when the field is empty
password: Yup.string()
.min(8, "Password must be at least 8 characters") // the message shown when the password input has less than 8 symbols
.required("Password is required"), // the message shown when the field is empty
});
const submitHandler = (values) => console.log(values)
return (
<div className="form-card">
<h1>Simple Registration Form</h1>
<Formik
initialValues={initialFormValues}
validationSchema={registrationValidationSchema} // applis the registration validation shema to the form
onSubmit={(v)=> submitHandler(v)}
>
<Form>
<div className="form-container">
<div className="input-container">
<label htmlFor="username" className="label">
Username
</label>
<Field
type="text"
id="username"
name="username"
className="text-field"
/>
<ErrorMessage name="username" component="div" />
</div>
<div className="input-container">
<label htmlFor="email" className="label">
Email
</label>
<Field
type="email"
id="email"
name="email"
className="text-field"
/>
<ErrorMessage name="email" component="div" />
</div>
<div className="input-container">
<label htmlFor="password" className="label">
Password
</label>
<Field
type="password"
id="password"
name="password"
className="text-field"
/>
<ErrorMessage name="password" component="div" />
</div>
</div>
<button type="submit" className="button">
Register
</button>
</Form>
</Formik>
</div>
);
};
export default RegistrationForm;
Congratulations, your React form is ready to use! How easy was that! Far better than using the standard useState
hook for each input field and implementing additional functions for state validation.
Conclusion
In this tutorial, we've created a basic registration form in a React app using Formik for form management and Yup for form validation. This amazing combination allows for a powerful yet straightforward approach to handling form state and input validation in React applications. Feel free to extend this example by adding more form fields, customizing validation messages and styling, or integrating backend services for form submission.
Happy coding!