Scroll to the first validation error in React
To scroll to the first validation error in React, create a <ScrollToFirstError> component which is responsible for scrolling to the first error in a form. This component can be put inside a form. We are passing the submit count and errors object as props to the <ScrollToFirstError> component so that when the submit count changes, the component will automatically scroll to the first error of the form.
In this tutorial, we are going to create a signup form and we are using Formik for the form management and Yup for validations.
Create <ScrollToFirstError> component for scroll to the first validation error
Let us create a <ScrollToFirstError> component first.
import { useEffect } from "react";
export const getFieldErrorNames = (formikErrors) => {
const transformObjectToDotNotation = (obj, prefix = "", result = []) => {
Object.keys(obj).forEach((key) => {
const value = obj[key];
if (!value) return;
const nextKey = prefix ? `${prefix}.${key}` : key;
if (typeof value === "object") {
transformObjectToDotNotation(value, nextKey, result);
} else {
result.push(nextKey);
}
});
return result;
};
return transformObjectToDotNotation(formikErrors);
};
const ScrollToFieldError = ({ submitCount, errors }) => {
useEffect(() => {
const fieldErrorNames = getFieldErrorNames(errors);
if (fieldErrorNames.length <= 0) return;
const elements = document.getElementsByName(fieldErrorNames[0]);
const element = elements[0];
if (!element) return;
// Scroll to first known error into view
element.scrollIntoView({ behavior: "smooth", block: "center" });
}, [submitCount]); // eslint-disable-line react-hooks/exhaustive-deps
return null;
};
export default ScrollToFieldError;
Here are take submitCount
and errors
object as props. When submitCount changes, getFieldErrorNames(errors)
function will return all the keys(keys will be the same as the field name in the case of Formik and yup) and take the first key in the array. Then scroll to that particular element by scrollIntoView({ behavior: "smooth", block: "center" })
function.
Use <ScrollToFirstError> in the form
We are using Formik and yup for Form Management.
You can install Formik and Yup using the below commands.
npm install formik yup
Our formik will looks like this:
const formik = useFormik({
initialValues: {
full_name: "",
email: "",
password: "",
confirm_password: ""
},
validationSchema: Yup.object({
full_name: Yup.string()
.min(2, "Mininum 2 characters")
.max(15, "Maximum 15 characters")
.required("Required!"),
email: Yup.string()
.email("Invalid email format")
.required("Required!"),
password: Yup.string()
.min(8, "Minimum 8 characters")
.required("Required!"),
confirm_password: Yup.string()
.oneOf([Yup.ref("password")], "Password's not match")
.required("Required!")
}),
onSubmit: values => {
alert(JSON.stringify(values, null, 2));
}
});
Next, use our <ScrollToFirstError> and pass submitCount and errors as:
<ScrollToFirstError submitCount={formik.submitCount} errors={formik.errors}/>
Our form will look like:
<div className="App">
<h1>Validation with Formik + Yup</h1>
<form onSubmit={formik.handleSubmit}>
<ScrollToFirstError submitCount={formik.submitCount} errors={formik.errors}/>
<div>
<label>Full Name</label>
<input
type="text"
name="full_name"
value={formik.values.full_name}
onChange={formik.handleChange}
/>
{formik.errors.full_name && formik.touched.full_name && (
<p>{formik.errors.full_name}</p>
)}
</div>
<div>
<label>Email</label>
<input
type="email"
name="email"
value={formik.values.email}
onChange={formik.handleChange}
/>
{formik.errors.email && formik.touched.email && (
<p>{formik.errors.email}</p>
)}
</div>
<div>
<label>Password</label>
<input
type="password"
name="password"
value={formik.values.password}
onChange={formik.handleChange}
/>
{formik.errors.password && formik.touched.password && (
<p>{formik.errors.password}</p>
)}
</div>
<div>
<label>Confirm Password</label>
<input
type="password"
name="confirm_password"
value={formik.values.confirm_password}
onChange={formik.handleChange}
/>
{formik.errors.confirm_password &&
formik.touched.confirm_password && (
<p>{formik.errors.confirm_password}</p>
)}
</div>
<div>
<button type="submit">Submit</button>
</div>
</form>
</div>
The <ScrollToFirstError> component can also be used without formik and yup. But make sure the error object keys are the same as the field name because, inside the <ScrollToFirstError> component, the scrolling element is identified by its name.
Conclusion
We have created a <ScrollToFirstError> component which is responsible for scrolling to the first error. This component can be placed inside any large form. Make sure to pass the submit count and errors object as props to the <ScrollToFirstError> component. When the submit count changes, the component will automatically scroll to the first error of the form.
On datainfinities.com, Read articles all around JavaScript, React, Node.js, PHP, Laravel, and Shopify.
Related Blogs
Get the Mouse Position (coordinates) in React
Can't Perform a React State Update on an Unmounted Component
Each child in a list should have a unique "key" prop
Programmatically update query params in React Router
Reset to the initial state in React
Get the current route using React Router
Create a Back button with React Router
How to check internet connection(online or offline) in React
Explore All Blogs