# Form Validation in React Using Formik

Form validation is one of the most important tasks when building an app and a form in particular. It’s one of the most tedious ones as well. Here is a unified approach to handling form validation using a neat library called `Formik`.

[Formik](https://formik.org/) is an open-source library for React and React Native that allows you to easily build forms. It takes care of repetitive and annoying tasks such as handling validation and submission, keeping track of values, errors, and visited or _touched_ fields.

The implementation in this guide is done in React. But the approach can easily be ported to a React Native app.

## Project Setup
### Dependency overview
- [Material UI](https://mui.com/material-ui/getting-started/overview/)
- [Formik](https://formik.org/)
- [Yup](https://github.com/jquense/yup): A simple object validation library that works perfectly with Formik.

### Initialise Project

Create a simple React project using the CRA toolchain.

```bash
npx create-react-app react-formik-example
```

### Install the dependencies

Navigate to the application and install these dependencies.

```bash
cd react-formik-example
npm install @mui/material @emotion/react @emotion/styled formik yup
```

## Design the Form

Let's create a simple registration form using Material UI. The path to this component will be `src/pages/Register.jsx`.

```jsx
import React from 'react';
import { Box, Button, TextField } from '@mui/material';

export const Register = () => {
  return (
    <Box mt={5}>
      <Box mb={1}>
        <TextField label="First Name" variant="outlined" />
      </Box>
      <Box mb={1}>
        <TextField label="Last Name" variant="outlined" />
      </Box>
      <Box mb={1}>
        <TextField label="Email Address" variant="outlined" type="email" />
      </Box>
      <Box mb={1}>
        <TextField label="Phone Number" variant="outlined" />
      </Box>
      <Box mb={1}>
        <TextField label="Password" variant="outlined" type="password" />
      </Box>
      <Box mb={1}>
        <TextField
          label="Confirm Password"
          variant="outlined"
          type="password"
        />
      </Box>

      <Button>Register</Button>
    </Box>
  );
};
```

Update App.js to display the `Register` component.

```jsx
import './App.css';
import { Register } from './pages/Register';

function App() {
  return (
    <div className="App">
      <Register />
    </div>
  );
}

export default App;
```

You should see the form if you run `npm start` now.

![A screenshot of a web browser showing form created in React using Material UI components](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mxza18006dc7gt7v3m8g.png)

## Create Validation Schema

Let's create a validation schema using Yup. The path to this file will be `src/schemas/register.form.js`.

```js
import * as yup from 'yup';

export const registerSchema = yup.object().shape({
  firstName: yup.string().required('First Name is required'),
  lastName: yup.string().required('Last Name is required'),
  email: yup.string().email('Invalid email').required('Email is required'),
  phoneNumber: yup
    .string()
    .matches(/^[0-9]+$/, 'Must be only digits')
    .min(9, 'Must be exactly 9 digits')
    .max(9, 'Must be exactly 9 digits')
    .required('Phone Number is required'),
  password: yup
    .string()
    .min(8, ({ min }) => `Password must be at least ${min} characters`)
    .required('Password is required'),
  confirmPassword: yup
    .string()
    .oneOf([yup.ref('password'), null], 'Passwords must match')
    .required('Confirm Password is required'),
});

export const registerInitialValues = {
  firstName: '',
  lastName: '',
  email: '',
  phoneNumber: '',
  password: '',
  confirmPassword: '',
};
```

Yup's API is pretty easy to understand and use. For example, the firstName field in the schema is mapped to required string schema, `yup.string().required('First Name is required')`. The form is invalid if no value is given for this field. Yup also allows you to change multiple validation rules for a single field. For example, the` phoneNumber` field has multiple validation rules such as matches, min, max, and required. Check out the Yup API documentation for more details.

## Add Formik

The simplest way to add Formik to the form is using the `useFormik` hook. Update `src/screens/Register.component.js` to use the hook.

```jsx
...
import { useFormik } from 'formik';
import { registerInitialValues, registerSchema } from '../schemas/register.form';

export const Register = () => {
  const formik = useFormik({
    initialValues: registerInitialValues,
    validationSchema: registerSchema,
    onSubmit: (values) => {
      console.log(values);
      Alert.alert(
        `Welcome, ${values.firstName}`,
        'Your account has been created.'
      );
    },
  });

...
```

Update the `TextField` components to handle the formik state for respective fields. For example, the First Name component should look like this:

```jsx
<TextField
  label="First Name"
  variant="outlined"
  onChange={formik.handleChange('firstName')}
  onBlur={formik.handleBlur('firstName')}
  value={formik.values?.firstName}
  error={formik.touched.firstName && Boolean(formik.errors.firstName)}
  helperText={formik.touched.firstName && formik.errors.firstName}
/>
```

Update the Button component to handle the form submission.

```jsx
<Button onClick={formik.handleSubmit}>Register</Button>
```

The Register component should look like this:

```jsx
import React from 'react';
import { Box, Button, TextField } from '@mui/material';
import { useFormik } from 'formik';
import {
  registerInitialValues,
  registerSchema,
} from '../schemas/register.form';

export const Register = () => {
  const formik = useFormik({
    initialValues: registerInitialValues,
    validationSchema: registerSchema,
    onSubmit: (values) => {
      console.log(values);
      alert(`Welcome, ${values.firstName}`, 'Your account has been created.');
    },
  });

  return (
    <Box mt={5}>
      <Box mb={1}>
        <TextField
          label="First Name"
          variant="outlined"
          onChange={formik.handleChange('firstName')}
          onBlur={formik.handleBlur('firstName')}
          value={formik.values?.firstName}
          error={formik.touched.firstName && Boolean(formik.errors.firstName)}
          helperText={formik.touched.firstName && formik.errors.firstName}
        />
      </Box>
      <Box mb={1}>
        <TextField
          label="Last Name"
          variant="outlined"
          onChange={formik.handleChange('lastName')}
          onBlur={formik.handleBlur('lastName')}
          value={formik.values?.lastName}
          error={formik.touched.lastName && Boolean(formik.errors.lastName)}
          helperText={formik.touched.lastName && formik.errors.lastName}
        />
      </Box>
      <Box mb={1}>
        <TextField
          label="Email Address"
          variant="outlined"
          type="email"
          onChange={formik.handleChange('email')}
          onBlur={formik.handleBlur('email')}
          value={formik.values?.email}
          error={formik.touched.email && Boolean(formik.errors.email)}
          helperText={formik.touched.email && formik.errors.email}
        />
      </Box>
      <Box mb={1}>
        <TextField
          label="Phone Number"
          variant="outlined"
          onChange={formik.handleChange('phoneNumber')}
          onBlur={formik.handleBlur('phoneNumber')}
          value={formik.values?.phoneNumber}
          error={
            formik.touched.phoneNumber && Boolean(formik.errors.phoneNumber)
          }
          helperText={formik.touched.phoneNumber && formik.errors.phoneNumber}
        />
      </Box>
      <Box mb={1}>
        <TextField
          label="Password"
          variant="outlined"
          type="password"
          onChange={formik.handleChange('password')}
          onBlur={formik.handleBlur('password')}
          value={formik.values?.password}
          error={formik.touched.password && Boolean(formik.errors.password)}
          helperText={formik.touched.password && formik.errors.password}
        />
      </Box>
      <Box mb={1}>
        <TextField
          label="Confirm Password"
          variant="outlined"
          type="password"
          onChange={formik.handleChange('confirmPassword')}
          onBlur={formik.handleBlur('confirmPassword')}
          value={formik.values?.confirmPassword}
          error={
            formik.touched.confirmPassword &&
            Boolean(formik.errors.confirmPassword)
          }
          helperText={
            formik.touched.confirmPassword && formik.errors.confirmPassword
          }
        />
      </Box>

      <Button onClick={formik.handleSubmit}>Register</Button>
    </Box>
  );
};
```

That's it. You have successfully created a form with validation using Formik.

Run `npm start` in your project's root directory to test.

## Conclusion
In this tutorial, you have learned how to create a form with validation in React using Formik (and Material UI). You have also learned how to use the `useFormik` hook to handle form state and yup to define validation rules.

### Source Code
The source code is available on [GitHub](https://github.com/daryllukas/react-formik-example).

