'React UseHookForm set focus when using useFieldArray

We have a pretty basic form that has a dynamic number of inputs. The number of inputs is being passed in as a prop to our SerialsForm component. We would like to set focus on the first input when this form renders.

const SerialsForm = ({qty}) => {
    const { handleSubmit, register, setFocus, control } = useForm();
    const { fields, append, prepend, remove } = useFieldArray({ name: 'serials', control });
    
    // Handle qty changes
    useEffect(() => {
        const oldVal = fields.length;
        if (qty > oldVal) {
            for (let i = oldVal; i < qty; i++) {
                append({ value: '' });
            }

        } else {
            for (let i = oldVal; i > qty; i--) {
                remove(i - 1);
            }
        }
    }, [qty, fields])

    const handleFormSubmit = (data) => {
        console.log(data)
    }
    

    return (
        <Form onSubmit={handleSubmit(handleFormSubmit)}>
            <div>
                {fields.map((item, i) => (
                    <FormGroup key={item.id}>
                        <FormControl
                            placeholder={`Serial #${i + 1}`}
                            {...register(`serials.${i}.value`)}  
                        />
                    </FormGroup>
                ))}
                <Button type='submit'>
                    <CheckCircle size={20} />
                </Button>
            </div>
        </Form>
    );
}

What We Have Tried:

  • adding { shouldFocus: true } and { shouldFocus: true, focusIndex: 0} as well as { shouldFocus: true, focusName: serials.0.value } as the second argument to append --> Nothing focuses
  • adding setFocus('serials.0.value'); at the end of useEffect. --> Error
  • adding autoFocus={i === 0} to the bootstrap FormControl (input) element. --> Nothing focuses

We have tried the same with prepend (we will likely end up using prepend because we want the first input focused)

Any idea of how to accomplish this would be greatly appreciated as we are not seeing a way to set focus outside of using a second argument to append, and that does not seem to be working.



Solution 1:[1]

What ended up working was adding a setTimeout to the end of the useEffect call.

useEffect(() => {
    // other useEffect code
    
    setTimeout(() => {
        if (qty) {
            setFocus('serials.0.value');
        }
    }, 0);
}, [qty, setFocus, ...yourOtherDeps])

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 BryceBy