Focus next input in React

I recently had to create a form that had a social security number field. Here was the markup.


const SSNField = () => {

  return (
    <>
      <input
        type="text"
        name="ssn-1"
        maxLength={3} />
      <input
        type="text"
        name="ssn-2"
        maxLength={2} />
      <input
        type="text"
        name="ssn-3"
        maxLength={4} />
    </>
  );
};

If you ever seen one of these fields, they’re usually made up of 3 <input> elements that make up 1 value.

Each field has a max length value, and have been given the property, name.

With that current user experience, the user types in the input field and gets stopped from entering anymore characters because of the maxLength property.

The user than has to manually click on the next field to continue. That’s really annoying.

A better user experience is to automatically focus to the next input field when they hit the max character length.

Here’s how I did it.

Focusing the next input after reaching the max length

The objective is to find the next input html element, and set that as the new focus point.

Only if the user has reached the max character length in the input field.


// Number of input fields that make up SSN
const numOfFields = 3;

const handleChange = e => {
  const { maxLength, value, name } = e.target;
  const [fieldName, fieldIndex] = name.split("-");

  // Check if they hit the max character length
  if (value.length >= maxLength) {
    // Check if it's not the last input field
    if (parseInt(fieldIndex, 10) < 3) {
      // Get the next input field
      const nextSibling = document.querySelector(
        `input[name=ssn-${parseInt(fieldIndex, 10) + 1}]`
      );

      // If found, focus the next field
      if (nextSibling !== null) {
        nextSibling.focus();
      }
    }
  }
}

Now that the onChange handler function has been created, it’s time to attach it to the input elements.


const SSNField = () => {

  return (
    <>
      <input
        type="text"
        name="ssn-1"
        maxLength={3}
        onChange={handleChange} />
      <input
        type="text"
        name="ssn-2"
        maxLength={2}
        onChange={handleChange} />
      <input
        type="text"
        name="ssn-3"
        maxLength={4}
        onChange={handleChange} />
    </>
  );
};

Full code with React useState

Here’s a bonus with React.useState().


// Number of input fields that make up SSN
const numOfFields = 3;

const useSSNFields = () => {
  const [ssnValues, setValue] = React.useState({
    ssn1: "",
    ssn2: "",
    ssn3: ""
  });

  return {
    handleChange: e => {
      const { maxLength, value, name } = e.target;
      const [fieldName, fieldIndex] = name.split("-");

      // Check if they hit the max character length
      if (value.length >= maxLength) {
        // Check if it's not the last input field
        if (parseInt(fieldIndex, 10) < 3) {
          // Get the next input field
          const nextSibling = document.querySelector(
            `input[name=ssn-${parseInt(fieldIndex, 10) + 1}]`
          );

          // If found, focus the next field
          if (nextSibling !== null) {
            nextSibling.focus();
          }
        }
      }

      setValue({
        ...value,
        [`ssn${fieldIndex}`]: value
      });
    }
  };
};

const SSNField = () => {
  const { handleChange } = useSSNFields();

  return (
    <>
      <input
        type="text"
        name="ssn-1"
        maxLength={3}
        onChange={handleChange} />
      <input
        type="text"
        name="ssn-2"
        maxLength={2}
        onChange={handleChange} />
      <input
        type="text"
        name="ssn-3"
        maxLength={4}
        onChange={handleChange} />
    </>
  );
};

I like to tweet about React and post helpful code snippets. Follow me there if you would like some too!