loading...

Next Input Focus on React Native

rvznkmrllh profile image Revzan Kamarullah ・3 min read

You must be familiar of using Tab key to focus to next element when browsing the web. It's a simple trick to make your browsing experience easier. Recently, I am making an app with React Native that has a one-time password (OTP) form. I am planning to give the same experience when user inserts a number the app will focus to the next TextInput.

This can be done by using ref attribute. Ref allows us to access the React component or DOM node that is going to be modified. Basically, what we are going to do are

  1. Create an array consist of React.createRef
  2. Add the ref attribute to the inputs
  3. Create a function to handle onChange from the inputs
  4. Focus the next input found
class OtpForm extends React.Component {
    constructor(props){
        super(props)
        this.inputRefs = [
            React.createRef(),
            React.createRef(),
            React.createRef(),
            React.createRef()
        ]
        // or 
        // this.inputRefs = Array(4).fill(React.createRef())
    }
}

Now above we already have an array of React.createRef. We only need 4 digits of OTP and one digit for each inputs. So we gonna add these elements to our render method.

...
   render(){
     return (
       <View>
         <Text>Enter OTP</Text>
         <View style={{ flexDirection: 'row' }}>
           <TextInput maxLength="1" />
           <TextInput maxLength="1" />
           <TextInput maxLength="1" />
           <TextInput maxLength="1" />
         </View>
       </View>
     )
   }
...

Notice that we have not add the ref attr to any TextInput. To make it easier we will rewrite those code to render TextInput based on our this.inputRefs length, then we add the ref attr.

...
   render(){
     return (
       <View>
         <Text>Enter OTP</Text>
         <View style={{ flexDirection: 'row' }}>
          {
            this.inputRefs.map((k, idx) => (
              <TextInput ref={r => this.inputRefs[idx] =  r} maxLength="1" />
            ))
          }
         </View>
       </View>
     )
   }
...

So basically, we iterate through our this.inputRefs using .map operator then we define the ref attr for each TextInput according to its index.

Now we already have our this.inputRefs array elements connected to each of the TextInput. The next thing is handling changes made by user. Since our TextInput only going to contain 1 digit number so we only need to handle onChange event. We are going to make a function _goNextAfterEdit that will set focus on the next input element.

class OtpForm extends React.Component {
    constructor(props){
        super(props)
        this.inputRefs = [
            React.createRef(),
            React.createRef(),
            React.createRef(),
            React.createRef()
        ]
    }

    // Pass the index of the current TextInput
    // then plus that with +1 
    _goNextAfterEdit(index){
        this.inputRefs[index+1].focus()
    }

    render(){
     return (
       <View>
         <Text>Enter OTP</Text>
         <View style={{ flexDirection: 'row' }}>
          {
            this.inputRefs.map((k, idx) => (
              <TextInput onChange={() => this._goNextAfterEdit(idx)} ref={r => this.inputRefs[idx] =  r} maxLength="1" />
            ))
          }
         </View>
       </View>
     )
   }
}

That's it!

Basically those code satisfy our purpose. But there are additional code you can add to avoid bugs or improve functionality, such as:

Validate the last TextInput

Since we render our TextInput based on the length of this.inputRefs, there will be a bug when user is editing the last TextInput provided inside the form.

...
   _goNextAfterEdit(index){
     if(index < this.inputRefs.length) {
       this.inputRefs[index+1].focus()
     }
   }
...

Handling > 1 digit text input

You might not want to use onChange event when having TextInput that receive word or > 1 digit character. I suggest using onSubmitEditing which fires when the user submit button from his/her keyboard.

Specify the input type

In React Native, you specify the keyboard displayed whenever the user is editing the TextInput. You can specify it by adding the keyboardType attr. For the complete list of keyboard type, https://facebook.github.io/react-native/docs/textinput.html#keyboardtype

Discussion

pic
Editor guide
Collapse
iampeters profile image
Peters Chikezie

hello, thanks for this. How do you do this for function components?

Collapse
franksitokawai profile image
Frank Nolasco Velasquez

Hi, were you able to solve it with functional components?