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
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
.
.
const formik = useFormik({
initialValues,
onSubmit,
validationSchema
})
.
.
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
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
}
- 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
}
.
.
- 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>
);
}
- 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)
This article should be deleted unless the example is made accessible for the reasons I explain in this video.
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
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.
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.
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...
sure man π
My codesandbox had an update to TextError as well by the way.
An output tag might be better than a div for form errors.
Yeah kind of right point