Twirlman
Twirlman

Reputation: 1189

How to set focus a ref using React-Hook-Form

How do you implement set focus in an input using React-Hook-Form, this is what their FAQ's "How to share ref usage" code here https://www.react-hook-form.com/faqs/#Howtosharerefusage

import React, { useRef } from "react";
import { useForm } from "react-hook-form";

export default function App() {
  const { register, handleSubmit } = useForm();
  const firstNameRef = useRef();
  const onSubmit = data => console.log(data);

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input name="firstName" ref={(e) => {
        register(e)
        firstNameRef.current = e // you can still assign to ref
      }} />
      <input name="lastName" ref={(e) => {
        // register's first argument is ref, and second is validation rules
        register(e, { required: true })
      }} />

      <button>Submit</button>
    </form>
  );
}

I tried set focusing the ref inside useEffect but it doesn't work:

useEffect(()=>{
   firstNameRef.current.focus();
},[])

Neither does inside the input:

<input name="firstName" ref={(e) => {
    register(e)
    firstNameRef.current = e;
    e.focus();
}} />

Upvotes: 28

Views: 55674

Answers (9)

XCZM
XCZM

Reputation: 1

Maybe my solution will help anybody cuz I was struggling a lot...

...

const ContentForm = () => {
  const [isPending, startTransition] = useTransition();

  const form = useForm<z.infer<typeof FormSchema>>({
    resolver: zodResolver(FormSchema),
    defaultValues: {
      word: '',
    },
  });

  const { handleSubmit, control, setFocus, resetField } = form;

  useEffect(() => {
    setFocus('word');
  }, [isPending]);

...

in this case every time after submit you focus on the input (I have one)

Upvotes: 0

staticvoid17
staticvoid17

Reputation: 90

You can use useMergeRefs from Chakra to combine the focus ref and the refs that react-hook-form uses, and pass that on to the input component:

import { 
  Input,
  FormControl,
  FormLabel,
  useMergeRefs
} from "@chakra-ui/react";

const focusRef = useRef(null);

<form onSubmit={handleSubmit(onSubmit)}>
  <FormControl isInvalid={Boolean(errors.newRlName)}>
    <FormLabel>name</FormLabel>
    <Input
      type="text"
      {...register("name")}
      tabIndex={1}
      ref={useMergeRefs(editRef, register("name").ref)}
    />
    <FormErrorMessage>{errors.name && errors.name?.message}</FormErrorMessage>
  </FormControl>
</form>

ref

Upvotes: 0

Ejiro Asiuwhu
Ejiro Asiuwhu

Reputation: 200

  const {
    register,
    handleSubmit,
    setFocus, // here
    formState: { errors },
  } = useForm<FormFields>({
    resolver: yupResolver(LoginSchema),
    mode: "onTouched",
  });



useEffect(() => {
    setFocus("email");
  }, [setFocus]);

Upvotes: 1

Gil Cohen
Gil Cohen

Reputation: 351

I can't comment (I don't have enough reputation), but without setting a timeout, setFocus didn't work. After adding a simple timeout from Subham's answer, it worked like a charm!

PS: Even adding a timeout of 0: setTimeout(() => setFocus(fieldName), 0) works. Can anyone explain?

Upvotes: 7

Chuma
Chuma

Reputation: 51

I think you can simply use ref={(el) => el.focus()} to set the focus. The catch here is to make sure no other element within your page is also setting focus right after that el.focus() call.

Upvotes: 0

Bryce
Bryce

Reputation: 1068

You can set the focus using the setFocus helper returned by the useForm hook (no need to use a custom ref):

 const allMethods = useForm();
 const { setFocus } = allMethods;

 ...

 setFocus('inputName');

https://react-hook-form.com/api/useform/setFocus

Upvotes: 21

Maged Mohamed
Maged Mohamed

Reputation: 905

If you using Version 7, you can check this link in the docs

https://www.react-hook-form.com/faqs/#Howtosharerefusage

Upvotes: 6

Rabinson
Rabinson

Reputation: 101

useEffect(() => {
if (firstNameRef.current) {
      register(firstNameRef.current)
      firstNameRef.current.focus()
    }
}, []);

<input name="firstName" ref={firstNameRef} />

Got this from : https://github.com/react-hook-form/react-hook-form/issues/230

Upvotes: 3

Steve S
Steve S

Reputation: 624

Are you using Typescript?

If so, replace...

const firstNameRef = useRef();

With...

const firstNameRef = useRef<HTMLInputElement | null>(null);

Upvotes: 5

Related Questions