how to set focus to next input on enter key press in react js with refs

Viewed 3659

Iam using multiple inputs inside maps i want to set focus to next input when i click enter in react Hooks. With the help of refs

Iam using material ui text field for getting input

I tried in react class component wihtout ref it works with error but in hooks it not works class compomnent code:

constructor(props) {
this.state = {}
}

inputRefs = [];

 _handleKeyPress = e => {
        const {currentTarget} = e;
            let inputindex = this.inputRefs.indexOf(currentTarget)
            if (inputindex < this.inputRefs.length - 1) {
                this.inputRefs[inputindex + 1].focus()
            }
            else {
                this.inputRefs[0].focus()
            }
      };

Inside render in added this within map function

this.state.data.map((data) => return (
<TextField 
     inputProps = {{onKeyPress:(e) => this.function1(e, data)}}
     onChange={this.changevaluefunction} 
     inputRef={ref => this.inputRefs.push(ref)} 
     onFocus={this.handleFocus}  ref={`input${id}`} /> ))
3 Answers

I have implemented the solution in a different way with the functional component. I have taken the 4 fields and seated its ref with the createRef hook.

I can see from your solution, you wanted to move focus to the next input element whenever you press Enter key on the current element.

I am passing the next target element argument in the onKeyUp handler along with the actual event and then detecting whether the Enter key is pressed or not. If Enter key is pressed and the targetElem is present then I am moving focus to the passed targetElem. By this way you have better control over the inputs.

You can see my solution here

https://codesandbox.io/s/friendly-leftpad-2nx91?file=/src/App.js

import React, { useRef } from "react";
import TextField from "@material-ui/core/TextField";
import "./styles.css";

const inputs = [
  {
    id: "fName",
    label: "First Name"
  },
  {
    id: "lName",
    label: "Last Name"
  },
  {
    id: "gender",
    label: "Gender"
  },
  {
    id: "address",
    label: "Address"
  }
];

export default function App() {
  const myRefs = useRef([]);

  const handleKeyUp = (e, targetElem) => {
    if (e.key === "Enter" && targetElem) {
      targetElem.focus();
    }
  };

  return (
    <div>
      {inputs.map((ipt, i) => (
        <TextField
          onKeyUp={(e) =>
            handleKeyUp(e, myRefs.current[i === inputs.length - 1 ? 0 : i + 1])
          }
          inputRef={(el) => (myRefs.current[i] = el)}
          id={ipt.id}
          fullWidth
          style={{ marginBottom: 20 }}
          label={ipt.label}
          variant="outlined"
          key={ipt.id}
        />
      ))}
    </div>
  );
}

You can convert this.inputRefs into a React ref so it persists through renders, and other than this you pretty much remove all references to any this object.

Example Component:

const LENGTH = 10;
const clamp = (min, max, val) => Math.max(min, Math.min(val, max));

export default function App() {
  const [data] = useState([...Array(LENGTH).keys()]);

  const inputRefs = useRef([]); // <-- ref to hold input refs

  const handleKeyPress = index => () => {                   // <-- enclose in scope
    const nextIndex = clamp(0, data.length - 1, index + 1); // <-- get next index
    inputRefs.current[nextIndex].focus();                   // <-- get ref and focus
  };

  return (
    <div className="App">
      {data.map((data, index) => (
        <div key={index}>
          <TextField
            inputProps={{ onKeyPress: handleKeyPress(index) }}   // <-- pass index
            inputRef={(ref) => (inputRefs.current[index] = ref)} // <-- save input ref
          />
        </div>
      ))}
    </div>
  );
}

Edit how-to-set-focus-to-next-input-on-enter-key-press-in-react-js-with-refs

If you are mapping the input field and want to focus on click, you can directly give the id attribute to the input and pass the array id.

After that, you can pass id inside a function as a parameter, and get it by document.getElementById(id).focus().

Related