'How to focus when an error occurs in react-hook-form Controller?

I am rendering a custom component using the Controller of react-hook-form.

If an error occurs when using register, focus is normal, but the Controller does not.

I was able to find a way to handle an error when the Custom Component processes only a single input, but I couldn't find a way to handle it when it has multiple inputs.

Form.js

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(),
    last: yup.string().required(),
  }),
});
function Form() {
  const {
    handleSubmit,
    control,
    formState: { errors },
  } = useForm({
    defaultValues: { name: { first: "", last: "" } },
    resolver: yupResolver(schema),
  });

  const onSubmit = (data) => console.log(data);

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <Controller
        name="name"
        control={control}
        rules={{ required: true }}
        render={({ field }) => (
          <CustomInput
            value={field.value}
            onChange={(value) => field.onChange(value)}
            errors={errors}
          />
        )}
      />
      <button type="submit">Send</button>
    </form>
  );
}

export default Form;

CustomInput.js

function CustomInput({ value, onChange, errors }) {
  const changeFirst = (e) => {
    onChange({ first: e.target.value, last: value?.last });
  };

  const changeLast = (e) => {
    onChange({ first: value?.first, last: e.target.value });
  };

  return (
    <div>
      <input type="text" value={value.first} onChange={changeFirst} />
      <input type="text" value={value.last} onChange={changeLast} />
      {errors?.name && (
        <p className="errmsg">
          {errors?.name?.first?.message || errors?.name?.last?.message}
        </p>
      )}
    </div>
  );
}

export default CustomInput;

​How can I get error focus when there are multiple inputs in a custom component?



Solution 1:[1]

Based on @NearHuscarl answer, I create the typescript version:

React.useEffect(() => {
    const firstError = (
      Object.keys(errors) as Array<keyof typeof errors>
    ).reduce<keyof typeof errors | null>((field, a) => {
      const fieldKey = field as keyof typeof errors;
      return !!errors[fieldKey] ? fieldKey : a;
    }, null);

    if (firstError) {
      setFocus(firstError);
    }
  }, [errors, setFocus]);

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Chrisk8er