Using Formik and Yup for Form validation
Tags: form, validation, reactjsdevelopment, react
Published: 2023-10-07 10:41:10

Form data validation can be a powerful tool for ensuring that your application's data meets the required criteria and is safe to use. However, it also comes with some pains, which are important to consider when implementing it. There are several issues to consider when creating a user experience for forms. These kinds of details distinguish between a bad experience and a good one. How, for instance, can the status of a form be changed? How about several validation methods? Setting up a form for submission can be verbose and be daunting sometimes.That's why I want to introduce Formik, small library that assists you with the three aspects that bother you the most:

- Getting values in and out of form state is very pretty and straightforward
- Handle form validation and error messages very well
- Handling form submission within the local state

Formik allows us to handle changes and maintain state (values, errors, and if the form is being submitted). On each submission, it also calls the validation method for us.

In this article, we will briefly introduce Formik and Yup, what they are, and what you'd want to use them for. We will learn how they can build a signup form and show you how to use Formik and Yup for form validation. 

## **About Formik and Yup**

Formik is a versatile library, and it allows you to choose when and how much to utilize it. Additionally, how much of the Formik library's capabilities we use is within our control. Formik may be used with Yup and its unique components, HTML input fields, personal validation rules, or both. When using Formik, form validation becomes simple. Moreover, together with Yup, they abstract all of React's form processing challenges.

Yup, it is a validator for JavaScript object schema. We'll concentrate on how it makes it easier to develop custom validation rules so we don't have to, even if it has many valuable features. An example Yup object schema for a sign-up form is shown below. 

```
import * as Yup from 'yup'

 const validationSchema = Yup.object().shape({
  email: Yup.string()
    .email('Invalid email address')
    .required('Email is required'),
  password: Yup.string()
    .required('Password is required')
    .min(8, 'Password must be at least 8 characters long')
    .matches(
      /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/,
      'Password must contain at least one uppercase letter, one lowercase     letter, one digit, and one special character'
    ),
  confirmPassword: Yup.string()
    .oneOf([Yup.ref('password'), null], 'Passwords must match')
    .required('Confirm Password is required'),

})

```

### **Prerequisite**
- A code editor (e.g. Visual Studio Code)
- NodeJS (version 16 or higher)
- Yarn (version 1.22.19)
- Basic JavaScript and React


### **Getting started**

You can install the dependencies/packages used in achieving this goal; these are the list of the dependencies.

- Formik
- Yup
- React-toastify
- TailwindCss 

TailwindCss requires extra configuration. Check out the official documentation [here](https://tailwindcss.com/docs/guides/vite)

You can also check out the final code on [GitHub](https://github.com/Taiwo17/Formik_Yup_guide).

` yarn add formik yup react-toastify`

**There are three different approaches to work with formik**

- useFormik hook.
- Formik with React context.
- withFormik as Higher-order-component.

In this tutorial, we will consider the usage of the useFormik hook due to its conciseness in code structure and the ability to make code more readable and cleaner.

**For the account signup  application:**

- Create a simple form file for the signup application.
- Include various HTML input elements for user input.

**Creating a Signup React Application**

Let's start by quickly scaffolding a React app using the create vite command.

` yarn create vite`

This prompts us to select the React development environment or the supporting frontend frameworks we want to use. Afterall, the yarn command is then used to install all of our dependent packages.

`yarn`

After installing the dependencies, we can now start our development environment.

`yarn dev`

We now have a working React  demo app.


![React demo app](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zfjdpy2lu2kpa0v40iyj.png)

**Creating our Signup form application**

First, creation of the  custom validation function to validate and verify the input that has been passed on.

```
// src/validate.js

export const validate = (values) => {
  let errors = {}
  if (!values.email) {
    errors.email = 'This field is required'
  } else if (!/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i.test(values.email)) {
    errors.email = 'Invalid email address'
  }
  if (!values.password) {
    errors.password = 'Please input your password'
  } else if (values.password.length < 8) {
    errors.password = 'The password must be greater than 8 characters'
  } else if (
    !/(?=.*[A-Z])(?=.*[a-z])(?=.*\d)(?=.*[@#$%^&+=]).*$/.test(values.password)
  ) {
    errors.password =
      'Password must contain at least one uppercase letter, one lowercase letter, one digit, and one special character (@#$%^&+=)'
  }

  if (!values.confirmPassword) {
    errors.confirmPassword = 'Please confirm your password'
  } else if (values.confirmPassword !== values.password) {
    errors.confirmPassword = 'Passwords do not match'
  }

  return errors
}

```

```
import { useFormik } from 'formik'
import { toast } from 'react-toastify'
import 'react-toastify/dist/ReactToastify.css'
import { validate } from './validate'


import './App.css'


function App() {
  // Using custom validation

  const formik = useFormik({
    initialValues: {
      email: '',
      password: '',
      confirmPassword: '',
    },
    validate,
    onSubmit: (values, { resetForm }) => {
      try {
        console.log(JSON.stringify(values, null, 2))
        toast.success('Account created successfully', {
          position: toast.POSITION.TOP_RIGHT,
        })
        resetForm()
      } catch (error) {
        console.log('Error occured', error.message)
      }
    },
  })
  return (
    <>
      <section className='bg-gray-50 dark:bg-gray-900'>
        <div className='flex flex-col items-center justify-center px-6 py-8 mx-auto md:h-screen lg:py-0'>
          <div className='w-full bg-white rounded-lg shadow dark:border md:mt-0 sm:max-w-md xl:p-0 dark:bg-gray-800 dark:border-gray-700'>
            <div className='p-6 space-y-4 md:space-y-6 sm:p-8'>
              <h1 className='text-xl font-bold leading-tight tracking-tight text-gray-900 md:text-2xl dark:text-white'>
                Create an account
              </h1>
              <form
                onSubmit={formik.handleSubmit}
                className='space-y-4 md:space-y-6'
              >
                {/*
                 *****
                 */}
                <button
                  type='submit'
                  className='w-full text-white bg-primary-600 hover:bg-primary-700 focus:ring-4 focus:outline-none focus:ring-primary-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center dark:bg-primary-600 dark:hover:bg-primary-700 dark:focus:ring-primary-800'
                >
                  Create an account
                </button>
              </form>
            </div>
          </div>
        </div>
      </section>
    </>
  )
}

export default App

```
In the code above, here is a thorough explanation of it.

- The `initialValues` property of the `useFormik` hook is an object that defines the initial values for the form fields. Here, a set of empty strings are being passed to the field names "email, password, confirmPassword" to indicate that inputs are expected in the forms.

- The `validate` function is exported from a separate file (`validate.js`), and it is used to validate form input values. It checks whether the email, password, and confirmPassword fields meet specific criteria and returns an object with error messages if validation fails.

- Below each input element, there are conditional error messages displayed if the field has been touched (`formik.touched`), and validation failed (`formik.errors`).

- The code utilizes the `toast` library to display a toast message when the form is successfully submitted.

- `resetForm` is called within the `onSubmit` handler function, allowing you to reset the form's fields to their initial values once the form has been processed.


Writing custom form validation can be complex and time-consuming, especially for forms with multiple fields and intricate validation rules. It involves writing and maintaining custom JavaScript code for each validation scenario. 

On the other hand, **Yup** offers a declarative way to define validation schemas using a simple and expressive syntax. This makes it easier to specify validation rules for each form field.


## **Validation with Yup**

Yup offers a simple but effective method for validating an object schema for your form controls.

Using Formik, form validation is simple. Together with Yup, they abstract all React's form processing challenges. With that, we can use Yup to generate the schema for the sign-in form.

Yup take care of the custom validations instead of doing it ourselves, which might be time consuming depending on how many fields there are.


**Take a look at this code snippet for our signup**

```
src/schema.js

import * as Yup from 'yup'

export const validationSchema = Yup.object().shape({
  email: Yup.string()
    .email('Invalid email address')
    .required('Email is required'),
  password: Yup.string()
    .required('Password is required')
    .min(8, 'Password must be at least 8 characters long')
    .matches(
      /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/,
      'Password must contain at least one uppercase letter, one lowercase letter, one digit, and one special character'
    ),
  confirmPassword: Yup.string()
    .oneOf([Yup.ref('password'), null], 'Passwords must match')
    .required('Confirm Password is required'),
})

```

Formik has a unique configuration prop for Yup called validationSchema that will automatically transform Yup's validation error messages into a pretty object whose keys match values/initial values/touched (just like any custom validation function would have to do). This is because Formik authors and users adore Yup so much.

Let's replace our custom validation function with validationSchema to demonstrate how Yup works.

_Exporting the Yup schema into our form, replacing the custom validation function_

```
import { useFormik } from 'formik'
import { toast } from 'react-toastify'
import 'react-toastify/dist/ReactToastify.css'
import { validationSchema } from './schema'
import './App.css'


function App() {
  const formik = useFormik({
    initialValues: {
      email: '',
      password: '',
      confirmPassword: '',
    },
    validationSchema: validationSchema,
    onSubmit: (values, { resetForm }) => {
      try {
        console.log(JSON.stringify(values, null, 2))
        toast.success('Account created successfully', {
          position: toast.POSITION.TOP_RIGHT,
        })
        resetForm()
      } catch (error) {
        console.log('Error occured', error.message)
      }
    },
  })
  return (
    <>
      <section className='bg-gray-50 dark:bg-gray-900'>
        <div className='flex flex-col items-center justify-center px-6 py-8 mx-auto md:h-screen lg:py-0'>
          <div className='w-full bg-white rounded-lg shadow dark:border md:mt-0 sm:max-w-md xl:p-0 dark:bg-gray-800 dark:border-gray-700'>
            <div className='p-6 space-y-4 md:space-y-6 sm:p-8'>
              <h1 className='text-xl font-bold leading-tight tracking-tight text-gray-900 md:text-2xl dark:text-white'>
                Create an account
              </h1>
              <form
                onSubmit={formik.handleSubmit}
                className='space-y-4 md:space-y-6'
              >
                {/*
                 *****
                 */}
                <button
                  type='submit'
                  className='w-full text-white bg-primary-600 hover:bg-primary-700 focus:ring-4 focus:outline-none focus:ring-primary-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center dark:bg-primary-600 dark:hover:bg-primary-700 dark:focus:ring-primary-800'
                >
                  Create an account
                </button>
              </form>
            </div>
          </div>
        </div>
      </section>
    </>
  )
}

export default App

```

**Congratulations!** You and Formik have produced a signup form that has intricate validation logic, and many error messages send error notifications to users in the proper context and at the appropriate moment 


## **Conclusion**

We've successfully examined the useFormik hook for form validation. We have shown how Formik may be used gradually and how Yup and Formik work together to handle form validation.