- Published on
How to Focus When an Error Occurs in React Hook Form Controller ?
- Authors
- Name
- Ripal & Zalak
How to Focus When an Error Occurs in React Hook Form Controller ?
React Hook Form (RHF) simplifies form handling in React applications. However, dealing with error focus on custom components wrapped by Controller
can be tricky. This blog will show you how to correctly set focus when errors occur in custom components.
Problem
Using register
in RHF, setting focus on fields with validation errors works seamlessly. However, with Controller
, the focus doesn't automatically shift to the input with the error, especially for custom components with multiple fields. Here's how you can solve this issue.
Example Scenario
In the following example, a custom component CustomInput
manages two fields (first
and last
) within an object. When an error occurs in either field, focus doesn't automatically shift to the problematic input.
import { Controller, useForm } from 'react-hook-form'
import CustomInput from './CustomInput'
import * as yup from 'yup'
const schema = yup.object({
name: yup.object().shape({
first: yup.string().required('First name is required'),
last: yup.string().required('Last name is required'),
}),
})
function Form() {
const {
handleSubmit,
control,
formState: { errors },
setFocus,
} = useForm({
defaultValues: { name: { first: '', last: '' } },
resolver: yupResolver(schema),
})
const onSubmit = (data) => console.log(data)
return (
<form onSubmit={handleSubmit(onSubmit)}>
<Controller
name="name"
control={control}
render={({ field }) => (
<CustomInput value={field.value} onChange={field.onChange} errors={errors} />
)}
/>
<button type="submit">Submit</button>
</form>
)
}
export default Form
Solution
To enable error focus for Controller
-managed inputs:
setFocus
and Watch for Errors
1. Use Use the setFocus
method from useForm
to programmatically focus on the first field with an error. Here's an example:
import React, { useEffect } from 'react'
import { useForm, Controller } from 'react-hook-form'
function Form() {
const {
handleSubmit,
control,
formState: { errors },
setFocus,
} = useForm({
defaultValues: { name: { first: '', last: '' } },
})
useEffect(() => {
if (errors.name) {
if (errors.name.first) setFocus('name.first')
else if (errors.name.last) setFocus('name.last')
}
}, [errors, setFocus])
const onSubmit = (data) => console.log(data)
return (
<form onSubmit={handleSubmit(onSubmit)}>
<Controller
name="name"
control={control}
render={({ field }) => (
<CustomInput value={field.value} onChange={field.onChange} errors={errors} />
)}
/>
<button type="submit">Submit</button>
</form>
)
}
export default Form
2. Ref Prop for Custom Inputs
Ensure your custom component properly forwards the ref
to the input element. For example:
function CustomInput({ value, onChange, errors, ref }) {
return (
<div>
<input
type="text"
value={value.first}
onChange={(e) => onChange({ ...value, first: e.target.value })}
ref={(el) => (ref.current = { ...ref.current, first: el })}
/>
<input
type="text"
value={value.last}
onChange={(e) => onChange({ ...value, last: e.target.value })}
ref={(el) => (ref.current = { ...ref.current, last: el })}
/>
{errors.name && <p>{errors.name.first?.message || errors.name.last?.message}</p>}
</div>
)
}
inputRef
for Material UI Components
3. Use If you're using Material UI, pass inputRef
in place of ref
:
<TextField
{...field}
inputRef={field.ref}
error={!!errors.name?.first}
helperText={errors.name?.first?.message}
/>
FAQs
Q: What happens if there are multiple errors?
Focus will shift to the first field with an error detected in the validation object. This behavior can be customized.
Q: Can this approach work with deeply nested fields?
Yes, by ensuring that the name
property correctly maps to the field's path, such as name.first
or address.city
.
Q: Is this compatible with all component libraries?
Yes, as long as the custom component forwards ref
or uses inputRef
(for libraries like Material UI).
Conclusion
By leveraging setFocus
and ensuring proper ref
forwarding, you can handle error focus seamlessly with Controller
in React Hook Form. This approach makes forms more user-friendly and enhances the overall experience.
If you found this guide helpful, share it with your network or leave a comment below!