DEV Community

Cover image for Form Handling | React | Part 2 | Error Validation
Shubham Tiwari
Shubham Tiwari

Posted on • Edited on

Form Handling | React | Part 2 | Error Validation

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

Creating validation

  • As we have created 3 input fields - name, email and company, we are going to create validation for those fields
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"),
})
.
.
Enter fullscreen mode Exit fullscreen mode
  • 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
.
.
 const formik = useFormik({
    initialValues,
    onSubmit,
    validationSchema
  })
.
.
Enter fullscreen mode Exit fullscreen mode

Creating Error component

Create a Component name "TextError" and paste this code there

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

Using the Error component

Just below all input fields, paste this code

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

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

Top comments (9)

Collapse
 
mellis481 profile image
Mike E • Edited

This article should be deleted unless the example is made accessible for the reasons I explain in this video.

Collapse
 
shubhamtiwari909 profile image
Shubham Tiwari

Well Accessibility is a concept itself and the title of the blog is Error handling. Accessibility is something developers should handle themselves as there can be slightly different way how they handle accessibility for screen readers

Collapse
 
mellis481 profile image
Mike E

Saying that setting proper ARIA for form fields in error and form error messages, and programmatically associating error messages to form fields shouldn't be part of an article on error handling is ridiculous.

Thread Thread
 
shubhamtiwari909 profile image
Shubham Tiwari

if you have read the article, it is clearly about the formik library, according to the logic, then i should also have covered proper css stylings for a better User experience that, proper form submission, a lot more things, its just the article itself is about error handling with formik, i showed how we can validate and show errors in form for React, about the ARIA thing, its developer choice how they want to implement it or whether they want to implement it or not.

Thread Thread
 
mellis481 profile image
Mike E

Ultimately, if a company uses the code in your example, they could get sued. That's very different than not showing CSS. Your solution is incomplete.

It took me about 3 minutes to make your example accessible. I'd encourage you to update your article. codesandbox.io/s/thirsty-khayyam-r...

Thread Thread
 
shubhamtiwari909 profile image
Shubham Tiwari

sure man πŸ™Œ

Thread Thread
 
mellis481 profile image
Mike E

My codesandbox had an update to TextError as well by the way.

Collapse
 
citronbrick profile image
CitronBrick

An output tag might be better than a div for form errors.

Collapse
 
shubhamtiwari909 profile image
Shubham Tiwari

Yeah kind of right point