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.

Form Style

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!

How can we help?

We're passionate about solving challenges and turning exciting ideas into reality, together with you. If you have any questions or need assistance with your projects, we're here to help. Don't hesitate to get in touch!

Book a Call
or send a message