Form and Form Validation in React using Formik and Yup

As a frontend and software engineer in general, security is one of the key concerns when building web applications, second only to performance. So taking time to prevent external form abuse by malicious users is never a wasted effort. We'll be working through form validation and form in React by building a contact form, using Yup and Formik.

Prerequisites

Before you begin this tutorial you'll need the following:

  • React knowledge
  • Yup Installed
  • Formik Installed

Installing React

setting up our project

 npx create-react-app yup-formik-validation
 cd yup-formik-validation
 yarn start

Formik

Formik is a library that manages form values(data), validation and error messages, and handling of form submissions. Making interacting with form as easy as a walk in the park.

Installing Formik

yarn add formik

Yup

Yup is a JavaScript schema builder for value parsing and validations.

Installing Yup

 yarn add yup

Initialize Module

After all installation we'll be working inside our App.js file.

app.js
import React, { useState } from 'react';
import { Formik, Field } from 'formik';
import * as Yup from 'yup';

Our next line of action is setting up our Form and form fields using Formik, we'll be working on 4 fields namely:

  • First Name Field
  • Last Name Field
  • Email Field
  • Message Field (using Textarea element)

Before we move forward let us talk about formik element and some of its attributes. Formik element housing both Form element and its child element (Field elements).

  <Formik>
    <Form>
      <Field></Field>
   </Form>
    ...
  </Formik>

Formik element also has some attributes that are required when setting up a form. Listed below:

  • InitialValues: it contains the initial values of our field elements.
    initialValues={{
     firstName: '',
     lastName: '',
     email: '',
     message: ''
    }}
    
  • ValidationSchema: houses our Yup validation schema, which we'll be talking about below.
> // declared outside of our App function.
const validationSampleSchema = Yup.object().shape({
   firstName: Yup.string().min(1, 'First Name is too 
      short!').required('First Name field is required'),
   lastName: Yup.string().min(1, 'Last Name is too 
      short!').required('Last Name field is required'),
   email: Yup.string().email('Invalid email').required('Email 
      field is required'),
   message: Yup.string().required('Message field is required')
})

Yup has different data type methods validation and conditions methods e.g min() and required()

validationSchema={customValidationSchema}

passing of our custom schema to the validationSchema attribute

  • onSubmit : submission function, which is an eventListener.
onSubmit={(values, { setSubmitting, resetForm }) => {
  // when the handleSubmit is triggered on our submit button 
     below, every expression and method actions get triggered

  // Reseting our form fields to empty
     resetForm({ values: "" });
}}

Rendering our Form and making Formik props and methods available

{(
  {
    setFieldValue,
    values,
    errors,
    touched,
    handleSubmit
  }) => (
     <>
       <form></form>
     <>
)}
<form>
   <div className='row'>
      <div className='col-md-6'>
         <div className="form-group mb-3">
            <label>First Name</label>
            <Field className="form-control" name="firstName" 
              value={values.firstName} placeholder="First 
              Name"/>
            {errors.firstName && touched.firstName && (<small 
            className="text-danger">{errors.firstName} 
            </small>)}
        </div>
      </div>
      <div className='col-md-6'>
         <div className="form-group mb-3">
            <label>Last Name</label>
            <Field name="lastName" className="form-control" 
             value={values.lastName} placeholder="Last Name" 
            />
            {errors.lastName && touched.lastName && (<small 
             className="text-danger">{errors.lastName} 
             </small>)}
         </div>
      </div>
      <div className='col-md-12'>
         <div className="form-group mb-3">
            <label>Email</label>
            <Field type="email" className="form-control" 
              value={values.email} name="email" 
              placeholder="Email" />
            {errors.email && touched.email && (<small 
             className="text-danger">{errors.email}</small>)}
          </div>
       </div>
       <div className="col-md-12">
          <div className="form-group mb-3">
            <label>Drop Message</label>
            <Field name="message">
                  {({
                      field,
                      meta,
                  }) => (
                 <div>
                   <textarea className="form-control" 
                    name="message" id="message"
                    placeholder="Type here" value= 
                    {values.message} rows="3" {...field} > 
                  </textarea>
                  {meta.touched && meta.error && ( <small 
                  className="text-danger">{meta.error}
                  </small>)}
                </div>
                )}
            </Field>
         </div>
       </div>
    </div>
    <button type="submit" className='btn btn-sm btn-success' 
     onClick={handleSubmit}>Submit</button>
 </form>

two Field attributes are important to us, in our above code:

  • name: automatically hook up inputs to Formik using the name attribute to match up with Formik state. <Field name={'email'}/> name attribute matches the property declared in our initialValues.
  • value: Formik access the value through the value attribute value={values.fieldName} e.g value={values.email}

Yup Formik Validation Contact Form

Errors

{errors.firstName && touched.firstName && (<small className="text-danger">{errors.firstName}</small>)}

whenever our field has been touched, and it contains an error, display it. The error setup above works with our firstName field.

Submit

<button type="submit" className='btn btn-sm btn-success' 
  onClick={handleSubmit}>Submit</button>

onClick eventlistener triggers our handleSubmit (Formik method), which is available to us when we rendered our form.

Updated onSubmit Formik attribute

onSubmit={(values, { setSubmitting, resetForm }) => {

  // assigning our values from the fields to the payload variable.   
  const payload = values;

  // we have a handleNext function that saves our contact form 
     field values into a result state.
  handleNext(payload);

  // Reseting our form fields to empty
  resetForm({ values: "" });
}}
const [showResult, setShowResult] = useState(false);
const [result, setResult] = useState({});

const handleNext = (payload) => {
    setResult(payload)
    setShowResult(true);
}

Yup Formik Validation Contact Form End Result

Demo Yup Formik Validation Contact Form Demo

Conclusion

Working with form in react is very tasking, coupled with trying to set up validation to our form fields, as we all know Form Validation is an integral part of building a web application, and Formik helps in working with forms in React doing the hard part and leaving us to worry more on other important parts in our web app development, same way Yup handles our validations.

Check out the following official documentations to get a broader explanation of our subject matter:

You can also find the full code source on GitHub:

Attributions

Have questions? Facing issues implementing?

Drop a comment let's work through them together.

Do you find this helpful?

You can follow me here on Dev and also on Twitter: