23
loading...
This website collects cookies to deliver better user experience
const initialValues = {
friends: [{ name: "", email: "" }],
}
const schema = Yup.object().shape({
friends: Yup.array(
Yup.object().shape({
name: Yup.string().required("Required"),
email: Yup.string().email("Invalid email").required("Required"),
})
)
.min(1)
.required(),
})
const errors = {
friends: [{ name: "Required" }, { email: "Invalid email" }],
}
<Field name={`friends[${index}].name`} />
) to reference nested values, and find an invalid input in the DOM.getFieldErrorNames()
function takes a Formik error as an argument, and returns an array of error field names using object dot-notation for array fields. For instance, given the error object from above, it'll return ['friends.0.name', 'friends.1.email']
, meaning that these attributes at that index have a validation error.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)
}
getFieldErrorNames()
needs to be executed when a user submits the form with invalid data. Unfortunately, Formik doesn't (yet) provide a sort of callback for a client-side failed submission, thus what we'll be doing instead, is listening to submitCount
changes, and executing our custom logic to scroll to an invalid input there.<ScrollToFieldError/>
component listens to submitCount
changes, and calls getFieldErrorNames()
when the form is invalid. If getFieldErrorNames()
returns any field error names, it'll query the first element by name, and scroll it into visible area of the window.export const ScrollToFieldError = () => {
const { submitCount, isValid, errors } = useFormikContext()
useEffect(() => {
if (isValid) return
const fieldErrorNames = getFieldErrorNames(errors)
if (fieldErrorNames.length <= 0) return
const element = document.querySelector(
`input[name='${fieldErrorNames[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
}
<ScrollToFieldError/>
component can be used within a Formik form (so that it has access to Formik's context), and whenever an invalid form submission occurs, it'll automatically scroll the first invalid input into the visible area of the window.