Form Handling | React | Part 2 | Error Validation
Tags: react, javascript, webdev, tutorial
Published: 2023-08-29 13:03:09

Hello everyone, today we will continue our series on React form handling with Error validation.

## What is error validation?
* It is simple validating form input fields and check for some particular cases where we don't want the user to enter some particular values.
* Examples could be empty input fields, minimum number of characters to enter in an input, email validation etc.

In the previous part, we had setup our form with initial values and submit handlers already, so i will refer to that same form in this part as well.

## Validation logic
* You can create a custom validation for your fields but we are going to use a library called "Yup" which will allow us to create validations easily.
* To install the yup library, enter this command in the terminal
```
npm i yup
```

## Creating validation
* As we have created 3 input fields -  name, email and company, we are going to create validation for those fields

```javascript
import * as Yup from 'yup'
.
.
const validationSchema = Yup.object({
  name: Yup.string().required("Name is required"),
  email: Yup.string().email("Email format invalid").required("Email is required"),
  company: Yup.string().required("Company is required"),
})
.
.
```
* As the code is explainable itself, we are creating validation for required field and for email validation as well.
* Now pass this validationSchema to the "useFormik" object
```javascript
.
.
 const formik = useFormik({
    initialValues,
    onSubmit,
    validationSchema
  })
.
.
```

## Creating Error component
Create a Component name "TextError" and paste this code there
```javascript
// TextError.js
import React from 'react'

function TextError (props) {
  return <div className='text-red-400 absolute -bottom-6 text-sm'>{props.children}</div>
}

export default TextError
```

## Using the Error component
Just below all input fields, paste this code
```javascript
import TextError from './TextError'
.
.
<input type='text' id='name' name='name' className='form-input' value={formik.values.name} onChange={formik.handleChange} />
{
  formik.errors.name ? <TextError>{formik.errors.name}. 
  </TextError> : null
}
.
.
<input type='email' id='email' name='email' className='form-input' value={formik.values.email} onChange={formik.handleChange} />
{
  formik.errors.email ? <TextError>{formik.errors.email}. 
  </TextError> : null
}
.
.
<input type='text' id='company' name='company' className='form-input' value={formik.values.company} onChange={formik.handleChange} />
{
  formik.errors.company ? <TextError>{formik.errors.company}. 
  </TextError> : null
}
```
* Just like we are accessing input values with "formik.value.fieldname", we are going to access to errors similar to it, "formik.errors.fieldname"
* We have added a condition that if the error exist, display it with TextError component else, it will be null, it will apply to all the 3 fields
* But, if you test it out, all the 3 fields will show error even if you enter in 1 field, that is a bad user experience as we need to show the error only to that field which is visited.
To fix this issue we are going to use 2 things - onBlur event and touched object in formik

## Checking for visited fields
To check for which field is visited and then show error for that particular field, add the onBlur event to all the inputs and use another condition with touched object.
* touched object contains the info about which input has been visited and which is not, it can accessed similar to values and errors, "formik.touched.fieldname".
* Now add onblur to inputs and touched condition to error message.
(Remember, just like handleChange and handleSubmit, handleBlur will be constant and should not be changed as it is inbuilt formik method)
```javascript
.
.
<input type='text' id='name' name='name' className='form-input' value={formik.values.name} onChange={formik.handleChange} onBlur={formik.handleBlur} />
{
  formik.touched.name && formik.errors.name ? <TextError>. 
  {formik.errors.name}</TextError> : null
}
.
.
 <input type='email' id='email' name='email' className='form-input' value={formik.values.email} onChange={formik.handleChange} onBlur={formik.handleBlur} />
{
   formik.touched.email && formik.errors.email ? <TextError>. 
   {formik.errors.email}</TextError> : null
}
.
.
 <input type='text' id='company' name='company' className='form-input' value={formik.values.company} onChange={formik.handleChange} onBlur={formik.handleBlur} />
{
  formik.touched.company && formik.errors.company ? 
  <TextError>{formik.errors.company}</TextError> : null
}
.
.
```
* We are checking here whether the field is visited using touched and if it is true, then we are checking whether the error exist, if it is true also, then we are going to show the error.


## Final Code
```javascript
import React from "react";
import { useFormik } from "formik";
import * as Yup from "yup";
import TextError from "./TextError";

const initialValues = {
  name: "Shubham",
  email: "",
  company: ""
};

const onSubmit = (values) => {
  console.log("Form data", values);
};

const validationSchema = Yup.object({
  name: Yup.string().required("Name is required"),
  email: Yup.string()
    .email("Email format invalid")
    .required("Email is required"),
  company: Yup.string().required("Company is required")
});

export default function App() {
  const formik = useFormik({
    initialValues,
    onSubmit,
    validationSchema
  });
  const isNameInError = formik.touched.name && formik.errors.name;
  const isEmailInError = formik.touched.email && formik.errors.email;
  const isCompanyInError = formik.touched.company && formik.errors.company;

  return (
    <div className="grid-container">
      <form className="form-container" onSubmit={formik.handleSubmit}>
        <div className="form-control">
          <label htmlFor="name">Name</label>
          <div className="relative">
            <input
              type="text"
              id="name"
              name="name"
              className="form-input"
              value={formik.values.name}
              onChange={formik.handleChange}
              onBlur={formik.handleBlur}
              aria-describedby="nameError"
              aria-invalid={isNameInError}
              aria-required
            />
            {isNameInError ? (
              <TextError id="nameError">{formik.errors.name}</TextError>
            ) : null}
          </div>
        </div>

        <div className="form-control">
          <label htmlFor="email">E-mail</label>
          <div className="relative">
            <input
              type="email"
              id="email"
              name="email"
              className="form-input"
              value={formik.values.email}
              onChange={formik.handleChange}
              onBlur={formik.handleBlur}
              aria-describedby="emailError"
              aria-invalid={isEmailInError}
              aria-required
            />
            {isEmailInError ? (
              <TextError id="emailError">{formik.errors.email}</TextError>
            ) : null}
          </div>
        </div>

        <div className="form-control">
          <label htmlFor="company">Company</label>
          <div className="relative">
            <input
              type="text"
              id="company"
              name="company"
              className="form-input"
              value={formik.values.company}
              onChange={formik.handleChange}
              onBlur={formik.handleBlur}
              aria-describedby="companyError"
              aria-invalid={isCompanyInError}
              aria-required
            />
            {isCompanyInError ? (
              <TextError id="companyError">{formik.errors.company}</TextError>
            ) : null}
          </div>
        </div>
        <button type="submit" className="form-submit">
          Submit
        </button>
      </form>
    </div>
  );
}
```
* In the final code, have added some aria attributes for screen readers accessibility

That's it for this part, in the next part, We are going to reduce some boilerplate for our form using Formik components

THANK YOU FOR CHECKING THIS POST
You can contact me on -
Instagram - https://www.instagram.com/supremacism__shubh/
LinkedIn - https://www.linkedin.com/in/shubham-tiwari-b7544b193/
Email - shubhmtiwri00@gmail.com

^^You can help me with some donation at the link below Thank you👇👇 ^^
☕ --> https://www.buymeacoffee.com/waaduheck <--

Also check these posts as well
https://dev.to/shubhamtiwari909/website-components-you-should-know-25nm

https://dev.to/shubhamtiwari909/smooth-scrolling-with-js-n56

https://dev.to/shubhamtiwari909/swiperjs-3802

https://dev.to/shubhamtiwari909/custom-tabs-with-sass-and-javascript-4dej