In Ionic 7, how do I set cursor focus on an IonInput field?

154 Views Asked by At

I'm using Ionic 7 and React 18. How do I cause a particular input on a form to automatically have the focus of the cursor when that component is loaded? I thought "autofocus" was the way

          <IonInput
          autofocus
            placeholder='First Name'
            value=''
          />

but that is not getting the cursor focus. An example can be seen here -- https://stackblitz.com/edit/an5yjh-xqjw5k?file=src%2FApp.tsx,src%2Fcomponents%2FMyForm.tsx .

Edit: Per the answer given, I tried this but the focus does not set to the only field on the page.

2

There are 2 best solutions below

2
On BEST ANSWER

You can try and use React's useRef and useEffect hooks:

import React, { useEffect, useRef } from 'react'
import { IonButton, IonInput } from '@ionic/react'

const MyForm = () => {
  const inputRef = useRef<HTMLIonInputElement>(null);

  useEffect(() => {
    setTimeout(() => { // Added a timeout to make sure the element is loaded
      inputRef.current?.setFocus();
    }, 0);
  }, []);

  return (
    <form>
      <IonInput
        ref={inputRef}
        placeholder='First Name'
        value=''
      />
    
      <IonButton type='submit'>Save And Continue</IonButton>
    </form>
  );
}

export default MyForm;

The useRef hook creates a reference (inputRef) to the IonInput element. The useEffect hook makes sure the focus is set on the IonInput when the component mounts. A timeout is used to make sure the DOM element is loaded before trying to set focus.
The IonInput is updated to use ref={inputRef} instead of the autofocus attribute.

That does set the focus on the IonInput field for 'First Name' when MyForm component is rendered.

You can see it in action in this stackblitz.


Is it possible that the setTimeout would be called and the element is not loaded? I was curious if there was a more foolproof way of only applying the focus once we're confident the input is on screen.

Yes, I have update the stackblitz.

Since the rendering of the IonInput is straightforward and not heavily dependent on asynchronous operations, the simplest and most effective approach should be to make sure the focus is set after the component and all its children are fully mounted.

import React, { useEffect, useRef } from 'react'
import { IonButton, IonInput } from '@ionic/react'

const MyForm = () => {
  const inputRef = useRef<HTMLIonInputElement>(null);

  useEffect(() => {
    if (inputRef.current) {
      const observer = new MutationObserver(() => {
        if (inputRef.current) {
          inputRef.current.setFocus();
          observer.disconnect();
        }
      });

      observer.observe(document, { childList: true, subtree: true });
    }
  }, []);

  return (
    <form>
      <IonInput
        ref={inputRef}
        placeholder='First Name'
        value=''
      />
    
      <IonButton type='submit'>Save And Continue</IonButton>
    </form>
  );
}

export default MyForm;

The MutationObserver will watch for changes in the DOM. When it detects changes, it checks if the IonInput is available and sets the focus.
The disconnecting observer (mentioned here) allows, once the focus is set, for the observer to be disconnected to prevent further unnecessary checks.

4
On

There is a method Ionic provides for IonInput component called: setFocus

The example provided will not work b/c you're using a submit type button, using a regular IonButton works.

const MyForm = () => {
  const firstNameInput = useRef<HTMLIonInputElement>(null);
  const handleButtonClick = () => {
    firstNameInput.current?.setFocus();
  };

  return (
    <>
      <form>
        <IonInput ref={firstNameInput} placeholder="First Name" value="" />
        <IonButton onClick={handleButtonClick}>Focus Input</IonButton>
        {/* <IonButton type="submit">Save And Continue</IonButton> */}
      </form>
    </>
 );
};