DEV Community

Daryl Lukas
Daryl Lukas

Posted on

Form Validation in React using Formik

This is a follow-up post to the last one on Form Validation in React Native using Formik. In this post, we will use a similar approach and create a web-based implementation using React. We will use the same validation schema (using Yup). We will also use the same form fields (using Material UI).

Project Setup

Initilize Project

Create a simple React project using the CRA toolchain.

npx create-react-app react-formik-example
Enter fullscreen mode Exit fullscreen mode

Install the dependecies

Navigate to the application and install these dependencies.

cd react-formik-example
npm install @mui/material @emotion/react @emotion/styled formik yup
Enter fullscreen mode Exit fullscreen mode

Design the form

Let's create a simple registration form using Material UI. The path to this component will be src/pages/Register.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>
  );
};
Enter fullscreen mode Exit fullscreen mode

Update App.js to display Register component.

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

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

export default App;
Enter fullscreen mode Exit fullscreen mode

If you run npm start now, you should see the form.

A screenshot of a web browser showing form created in React using Material UI components

Create Validation Schema

Let's create a validation schema using Yup. The path to this file will be src/schemas/register.form.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: '',
};
Enter fullscreen mode Exit fullscreen mode

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 by using the useFormik hook. Update src/screens/Register.component.js to use the hook

...
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.'
      );
    },
  });

...
Enter fullscreen mode Exit fullscreen mode

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

<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}
/>
Enter fullscreen mode Exit fullscreen mode

Update the Button component to handle the form submission

<Button onClick={formik.handleSubmit}>Register</Button>
Enter fullscreen mode Exit fullscreen mode

The Register component should look like this

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>
  );
};
Enter fullscreen mode Exit fullscreen mode

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

Run npm start 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

Available on GitHub.

New to React?

I'm offering a 1-on-1, pair programming-styled, remote training in React. Apply here.

Top comments (2)

Collapse
 
erik_slagter profile image
Erik Slagter

Damn, That’s a lot duplicate code. Maybe you can create a formik input component to remove all the duplication?

That would make it a lot more readable.

Collapse
 
daryllukas profile image
Daryl Lukas

I agree. It was a quick example. However, you can not use useFormik with a formik input component. That will require using the Context API.

formik.org/docs/api/useFormik