317

I defined two TextInput fields as follows:

<TextInput 
   style = {styles.titleInput}
   returnKeyType = {"next"}
   autoFocus = {true}
   placeholder = "Title" />
<TextInput
   style = {styles.descriptionInput}          
   multiline = {true}
   maxLength = {200}
   placeholder = "Description" />

But after pressing the "next" button on my keyboard, my react-native app isn't jumping to the second TextInput field. How can I achieve that?

Thanks!

andreaswienes
  • 3,401
  • 2
  • 14
  • 10
  • Mitch's answer (currently the 3rd one down) works for me on v0.42. – Lawrence Mar 09 '17 at 21:21
  • 2
    For people on React `v16.8.0` or above I'd recommend the answer provided by @Eli Johnson towards the bottom. React has deprecated many uses of `ref` provided in solutions below. – thedeg123 Mar 31 '20 at 01:56

24 Answers24

460

Set the second TextInput focus, when the previous TextInput's onSubmitEditing is triggered.

Try this

  1. Adding a Ref to second TextInput
    ref={(input) => { this.secondTextInput = input; }}

  2. Bind focus function to first TextInput's onSubmitEditing event.
    onSubmitEditing={() => { this.secondTextInput.focus(); }}

  3. Remember to set blurOnSubmit to false, to prevent keyboard flickering.
    blurOnSubmit={false}

When all done, it should looks like this.

<TextInput
    placeholder="FirstTextInput"
    returnKeyType="next"
    onSubmitEditing={() => { this.secondTextInput.focus(); }}
    blurOnSubmit={false}
/>

<TextInput
    ref={(input) => { this.secondTextInput = input; }}
    placeholder="secondTextInput"
/>
stephen.hanson
  • 9,014
  • 2
  • 47
  • 53
boredgames
  • 11,254
  • 5
  • 25
  • 17
  • 79
    Worth to mention, that `onSubmitEditing` callback is called after `blur` event. So the keyboard may go crazy if focused on next element immediately. So it might be helpful to set `blurOnSubmit={false}` to all elements in form but leave at `true` on last element, to allow **Done** button to blur the last input. – e1dar Aug 01 '16 at 17:37
  • 11
    This doesn't work anymore, as of v0.36. There is no method "focus" on the component. How should we do this now? – Mitch Nov 01 '16 at 05:56
  • @Mitch could you find an answer for this? – tarkanlar Nov 27 '16 at 19:44
  • @tarkanlar Yes. My solution feels like a hack, but I *think* it is the best solution available right now. See my answer below. – Mitch Nov 28 '16 at 04:47
  • 4
    @Mitch works fine on 0.40.0. Might have been a bug in the version you were running. – vikki Feb 06 '17 at 06:24
  • Use funcution setFocus() instead focus() – Raviranjan Mishra Apr 04 '17 at 09:54
  • `this.refs.SecondInput.focus();` or `this.refs.SecondInput.setFocus();` do not work . Using `react-native 0.45.1` – jasan Jun 15 '17 at 20:54
  • @jasan it worked for me. Make sure to use `onEndEditing` instead of `onSubmitEditing`. – liver Jul 04 '17 at 15:31
  • I have just one input and I need to focus itself after each submit but I'm still trying to achieve it. Some idea? I'm using the example in https://facebook.github.io/react/docs/refs-and-the-dom.html for RN 0.44. `onEndEditing` doesn't work to me because I have other buttons in the view that need to keep working. – roadev Jul 13 '17 at 02:27
  • @jasan @Olivia I'm using `onSubmitEditing` on `react-native 0.45.1` just fine. – MattyK14 Jul 13 '17 at 12:59
  • How can we focus react-native Picker? – Adnan Ali Oct 22 '17 at 09:24
  • 1
    I am using react-native : 0.48.4 this sample code is not working @boredgames – achu Oct 24 '17 at 07:54
  • 4
    Using RN 0.49, adding `blurOnSubmit={false}` to prevent keyboard flickering caused this to stop working, any one that knows what's going on? – nabil london Nov 09 '17 at 00:12
  • Tried this in RN 0.47 aaaaand... IT WORKS! – Walter Monecke Dec 20 '17 at 09:54
  • 20
    For anyone who couldn't manage to make `focus` work, make sure you don't use a wrapper for `TextInput` component. If you have a say `CustomTextInput` component that wraps `TextInput`, you need to implement `TextInput` blur and focus methods for that component so it will work as expected. – Cihad Turhan Jan 27 '18 at 00:18
  • Works with 0.53 – anni Feb 24 '18 at 23:53
  • how can we add next button in keyboard with keyboardType=phone-pad''?? – Rishabh Bhardwaj Apr 11 '18 at 12:21
  • @RishabhBhardwaj i believe phone pad does not have a next button – MoralCode Jul 16 '18 at 00:17
  • 1
    Not working on RN 0.59.3 (there isn't a method named `focus()` on `TextInput` (no, I'm not using a wrapper) – Can Poyrazoğlu May 08 '19 at 01:58
  • @CihadTurhan I recommend spreading props and passing that down to `CustomTextInput` so that the TextInput props can be used. Ex: `` – grant Aug 24 '20 at 22:33
  • 3
    Is there any cleaner way with formik? I'm building a form with 15 inputs I don't want to have a component with 15 useRef hooks my component is going to be really messy – Emad Baqeri Apr 28 '21 at 21:24
124

Thought I would share my solution using a function component... 'this' not needed!

React 16.12.0 and React Native 0.61.5

Here is an example of my component:

import React, { useRef } from 'react'
...


const MyFormComponent = () => {

  const ref_input2 = useRef();
  const ref_input3 = useRef();

  return (
    <>
      <TextInput
        placeholder="Input1"
        autoFocus={true}
        returnKeyType="next"
        onSubmitEditing={() => ref_input2.current.focus()}
      />
      <TextInput
        placeholder="Input2"
        returnKeyType="next"
        onSubmitEditing={() => ref_input3.current.focus()}
        ref={ref_input2}
      />
      <TextInput
        placeholder="Input3"
        ref={ref_input3}
      />
    </>
  )
}
peterh
  • 11,875
  • 18
  • 85
  • 108
Eli Johnson
  • 1,492
  • 1
  • 10
  • 10
  • 10
    not working. undefined is not object evaluating _this2.ref_input2.current,please help – Deep Adhia Feb 20 '20 at 06:24
  • Can you provide a more complete example of your code? – Eli Johnson Feb 21 '20 at 22:07
  • 2
    might be better to use useRef in functional component than createRef – Eric Ahn Feb 26 '20 at 03:44
  • @hyuklee You are indeed correct sir, I have updated... thanks for the heads up! Cheers! – Eli Johnson Feb 26 '20 at 12:00
  • 5
    For those who like keeping up with the latest react updates, this is THE ANSWER. – Ren Apr 21 '20 at 18:31
  • 14
    Nice solution. I recommend including `blurOnSubmit={false}` on the first two inputs to prevent keyboard flicker – grant Aug 26 '20 at 18:15
  • 1
    Worked great! Most simple and straightforward solution here. – Amir5000 Sep 10 '20 at 23:45
  • 1
    ref_input2.current.focus() didnt work, the solution I used is ref_input2.current._root.focus() – 404notBrighton Oct 03 '20 at 17:54
  • Hey, is it possible to have an object instead of a single ref for every field? – MorenoMdz Oct 05 '20 at 13:41
  • 12
    For those that are using a wrapper component for Text Input, I found that I needed to pass down Ref using [React.forwardRef()](https://reactjs.org/docs/forwarding-refs.html) and then pass ref as prop to Text Input – Bader Oct 07 '20 at 17:30
  • @EliJohnson I am trying to implement your solution here, https://stackoverflow.com/questions/64469245/change-focus-automatically-to-next-input-with-react-native but am having issues, any feedback is appreciated. Thanks! – kinzito17 Oct 21 '20 at 19:58
  • 1
    THANK YOU fml the time i spent on this – AiSirachcha21 Nov 02 '20 at 18:49
  • 2
    @404notBrighton Your solution worked. I am using expo sdk 41 that uses RN 0.63 – Cyril Ikelie Jun 02 '21 at 00:11
  • @grant, I needed that option also :) – cross19xx Sep 26 '21 at 13:49
  • 2
    Anybody know how to do this with TypeScript? React complains when you assign the ref defined by `useRef` to the `ref` prop, amazingly... EDIT: just need to add a union type with `null`, duh. See more here: https://stackoverflow.com/questions/69313784/react-native-text-input-focus-with-useref-using-typescript – fullStackChris Jan 19 '22 at 14:25
  • Its also better to use null checks before accessing it. Like ref_input2?.current?.focus(); here it won't effect, but if you access ref of ScrollView it will crash. – Faisal Hassan Mar 29 '22 at 09:47
  • 5
    for anyone using typescript and getting Object is possibly 'null'. change these two lines: `const ref_input2 = useRef(null);` and `onSubmitEditing={() => ref_input2.current?.focus()}` – Carlos Reyes Oct 05 '22 at 17:15
75

You can do this without using refs. This approach is preferred, since refs can lead to fragile code. The React docs advise finding other solutions where possible:

If you have not programmed several apps with React, your first inclination is usually going to be to try to use refs to "make things happen" in your app. If this is the case, take a moment and think more critically about where state should be owned in the component hierarchy. Often, it becomes clear that the proper place to "own" that state is at a higher level in the hierarchy. Placing the state there often eliminates any desire to use refs to "make things happen" – instead, the data flow will usually accomplish your goal.

Instead, we'll use a state variable to focus the second input field.

  1. Add a state variable that we'll pass as a prop to the DescriptionInput:

    initialState() {
      return {
        focusDescriptionInput: false,
      };
    }
    
  2. Define a handler method that will set this state variable to true:

    handleTitleInputSubmit() {
      this.setState(focusDescriptionInput: true);
    }
    
  3. Upon submitting / hitting enter / next on the TitleInput, we'll call handleTitleInputSubmit. This will set focusDescriptionInput to true.

    <TextInput 
       style = {styles.titleInput}
       returnKeyType = {"next"}
       autoFocus = {true}
       placeholder = "Title" 
       onSubmitEditing={this.handleTitleInputSubmit}
    />
    
  4. DescriptionInput's focus prop is set to our focusDescriptionInput state variable. So, when focusDescriptionInput changes (in step 3), DescriptionInput will re-render with focus={true}.

    <TextInput
       style = {styles.descriptionInput}          
       multiline = {true}
       maxLength = {200}
       placeholder = "Description" 
       focus={this.state.focusDescriptionInput}
    />
    

This is a nice way to avoid using refs, since refs can lead to more fragile code :)

EDIT: h/t to @LaneRettig for pointing out that you'll need to wrap the React Native TextInput with some added props & methods to get it to respond to focus:

    // Props:
    static propTypes = { 
        focus: PropTypes.bool,
    } 

    static defaultProps = { 
        focus: false,
    } 

    // Methods:
    focus() {
        this._component.focus(); 
    } 

    componentWillReceiveProps(nextProps) {
        const {focus} = nextProps; 

        focus && this.focus(); 
    }
Stedman Blake
  • 899
  • 6
  • 5
  • I'm using RN 0.19 and this approach isn't working for me. Setting focus={} on a TextInput doesn't seem to have any effect when the prop's value changes. – Lane Rettig Feb 22 '16 at 20:07
  • @LaneRettig can you make sure that your component is re-rendering upon changes to `this.state.focusDescriptionInput`? You can just log it in the render() method (`console.log(this.state.focusDescriptionInput);`) and see if it prints out upon calling `handleTitleInputSubmit()`. Also, make sure that the value being set to either `true` or `false`. – Stedman Blake Feb 23 '16 at 20:42
  • I tried this again. Confirmed that the variables are being set properly, and that the view is being re-rendered. Setting focus={this.state.foo} on a TextInput does not work in the current version of RN, as far as I can tell! – Lane Rettig Feb 27 '16 at 21:21
  • 2
    @LaneRettig You're totally right -- thanks for pointing that out. We wrap RN TextInput with some added props and methods -- please see the bottom of the answer w/ those additions and let me know if you have any further issues! – Stedman Blake Feb 28 '16 at 23:19
  • 4
    Cool. You should submit this as a PR to RN. I'm surprised this isn't already supported out of the box. – Lane Rettig Feb 28 '16 at 23:33
  • 11
    what if you click next on keyboard, and then click directly on first input? focus goes back to second which is bad experience with that solution – Piotr Apr 08 '16 at 14:21
  • This is a much messier solution than the first solution. The best solution would be a memo-bind type solution: https://github.com/airbnb/javascript/issues/659 and specifically https://github.com/supnate/memobind – chapinkapa May 15 '16 at 02:16
  • 2
    @chapinkapa Can you give an example of how this would work with the memobind solution? – Stephen Horvath Oct 02 '16 at 21:39
  • 2
    How is `this._component` initialized? – Petr Peller Jul 21 '17 at 22:46
  • I couldn't get it to work. Could you please post the complete code? – Singh Dec 25 '17 at 12:18
  • 5
    I don't love this solution, in particular because it doesn't scale well for even slightly longer forms of 5-6 elements, where you'd need a focus boolean in state for each element & manage them all accordingly. – davidgoli Mar 20 '18 at 21:30
  • 24
    Interestingly, the docs also state: "There are a few good use cases for refs: Managing focus, text selection, or media playback..." So in this case, using refs for focusing text input would be a valid use of the tool. – Noah Allen Jun 19 '18 at 03:33
  • 2
    doest text input have prop 'focus'? I just check the doc, it aint – angry kiwi May 23 '19 at 14:48
  • This solution still may be useful for specific use-cases. I'll give it a try since I do need to use the ref for my testing framework (https://github.com/pixielabs/cavy) and I can't use the refs because of it – Guillaume Munsch May 28 '19 at 10:08
  • Is this still working? This is not documented: https://reactnative.dev/docs/textinput – Sharcoux Mar 11 '20 at 13:36
  • But you have used a ref here, and focus is not really a state that belongs to an individual component, it's a state that applies to the enitire screen. So passing a prop to indicate whether it is focused seems odd. when using refs, whichever component's focus method was called last would be the one in focus. – Avin Kavish Aug 09 '20 at 06:01
28

As of React Native 0.36, calling focus() (as suggested in several other answers) on a text input node isn't supported any more. Instead, you can use the TextInputState module from React Native. I created the following helper module to make this easier:

// TextInputManager
//
// Provides helper functions for managing the focus state of text
// inputs. This is a hack! You are supposed to be able to call
// "focus()" directly on TextInput nodes, but that doesn't seem
// to be working as of ReactNative 0.36
//
import { findNodeHandle } from 'react-native'
import TextInputState from 'react-native/lib/TextInputState'


export function focusTextInput(node) {
  try {
    TextInputState.focusTextInput(findNodeHandle(node))
  } catch(e) {
    console.log("Couldn't focus text input: ", e.message)
  }
}

You can, then, call the focusTextInput function on any "ref" of a TextInput. For example:

...
<TextInput onSubmit={() => focusTextInput(this.refs.inputB)} />
<TextInput ref="inputB" />
...
Mitch
  • 1,437
  • 1
  • 13
  • 17
  • I couldn't make this work maybe because I use redux-form – tarkanlar Nov 28 '16 at 15:03
  • 1
    Works awesome but if anyone uses redux-form should do something like this. ` focusTextInput(this._password)} />` and ref should be like this ` this._password = e}/>` – tarkanlar Nov 28 '16 at 22:18
  • 1
    I had to use 'onSubmitEditing' to make this work but great solution none the less. – Adam Jakiela Dec 21 '16 at 14:55
  • 3
    Works great in 0.42. – Lawrence Mar 09 '17 at 21:20
  • 1
    @tarkanlar can you share code snippet for the solution? I can't seem to focus when using redux-form Field, using just TextInput works, fine – jasan Jun 16 '17 at 08:14
  • Works with 0.46 – Sound Blaster Aug 10 '17 at 10:05
  • Works in 0.46 with a small change: `import * as TextInputState from 'react-native/lib/TextInputState'` – bds Oct 13 '17 at 17:27
  • 4
    `calling focus() on a text input node isn't supported any more` => bold claim, source? Calling `focus()` works fine with v0.49.5 + `TextInputState` is not documented while `focus()` and `blur()` are mentioned: http://facebook.github.io/react-native/releases/next/docs/textinput.html – tanguy_k Oct 31 '17 at 00:27
  • @tanguy_k My source is the RN source code as of v0.36 . It seems that this has been addressed in later versions of RN. – Mitch Nov 09 '17 at 16:51
  • I can confirm that `focus()` works with RN 0.57, I got it to work very similarly to this answer: `onSubmitEditing={() => (this.refs.password as TextInput).focus()}` – riqitang Jan 10 '19 at 15:46
25

I created a small library that does this, no code change needed other than replacing your wrapping view and import of TextInput:

import { Form, TextInput } from 'react-native-autofocus'

export default () => (
  <Form>
    <TextInput placeholder="test" />
    <TextInput placeholder="test 2" />
  </Form>
)

https://github.com/zackify/react-native-autofocus

Explained in detail here: https://zach.codes/autofocus-inputs-in-react-native/

zackify
  • 5,314
  • 2
  • 22
  • 28
  • Excellent pattern for achieving this result. Should be top answer from ease of use stand point. Looks like I can easily edit my custom FormInput (TextInput extensions) to still work with your Form inputs. Mind if I include it to your answer if for further example? – Jack Robson Aug 21 '17 at 22:42
  • Sure! I know... I posted this on the other popular post about this but got in trouble for duplicates. Just trying to help because I know how annoying this problem is!! – zackify Aug 22 '17 at 03:02
  • 1
    This is great if you have a bunch of TextInputs right after each other but if you want to add styling between them it breaks down. Thanks for the contribution though. – GenericJam Oct 23 '17 at 02:26
  • Feel free to adjust the code. I’m sure you could make a way that would skip over elements that are not text inputs. Shouldn’t be too hard to do. – zackify Oct 23 '17 at 04:45
  • 1
    This does not build for production RN@0.47.2 – Max Phillips Dec 28 '17 at 10:39
  • Feel free to make a pr, I'll check it out when i get some free time! – zackify Jan 09 '18 at 16:33
  • Excellent Work! – ROI Sep 10 '18 at 04:22
  • This breaks in production. – Aaron Feb 07 '19 at 19:44
15

Using react-native 0.45.1 I also encountered problems trying to set focus on a password TextInput after pressing return key on a username TextInput.

After having tried most of the top rated solutions here on SO I found a solution on github that fulfilled my needs: https://github.com/shoutem/ui/issues/44#issuecomment-290724642

To sum it up:

import React, { Component } from 'react';
import { TextInput as RNTextInput } from 'react-native';

export default class TextInput extends Component {
    render() {
        const { props } = this;

        return (
            <RNTextInput
                {...props}
                ref={(input) => props.inputRef && props.inputRef(input)}
            />
        );
    }
}

And then I use it like this:

import React, {Component} from 'react';
import {
    View,
} from 'react-native';
import TextInput from "../../components/TextInput";

class Login extends Component {
    constructor(props) {
        super(props);
        this.passTextInput = null
    }

    render() {
        return (
            <View style={{flex:1}}>
                <TextInput
                    style={{flex:1}}
                    placeholder="Username"
                    onSubmitEditing={(event) => {
                        this.passTextInput.focus()
                    }}
                />

                <TextInput
                    style={{flex:1}}
                    placeholder="Password"
                    inputRef={(input) => {
                        this.passTextInput = input
                    }}
                />
            </View>
        )
    }
}
kuhr
  • 582
  • 8
  • 18
15

Combining @Eli Johnson's solution for functional components with @Rodrigo Tessarollo's solution for a CustomTextInput:

import React, { useRef } from 'react';
import { CustomTextInput } from 'path/to/CustomTextInput';
...


export const MyFormComponent = () => {

  const ref_to_input2 = useRef();

  return (
    <>
      <CustomTextInput
        placeholder="Input 1"
        autoFocus={true}
        returnKeyType="next"
        onSubmitEditing={() => ref_to_input2.current.focus()}
      />
      <CustomTextInput
        placeholder="Input 2"
        returnKeyType="done"
        refInner={ref_to_input2}
        onSubmitEditing={/* Do something! */}
      />
    </>
  )
}

and in your CustomTextInput component:

import { TextInput } from "react-native";
export const CustomTextInput = (props) => {
  <TextInput
        ref={props.refInner}
        {...props}
  />
}
Joe
  • 442
  • 5
  • 18
  • Have you tried to have a single Ref for all inputs? Your solution worked, but in big forms it is quite verbose to have a single ref for each input. – MorenoMdz Jun 18 '21 at 19:12
12

For me on RN 0.50.3 it's possible with this way:

<TextInput 
  autoFocus={true} 
  onSubmitEditing={() => {this.PasswordInputRef._root.focus()}} 
/>

<TextInput ref={input => {this.PasswordInputRef = input}} />

You must see this.PasswordInputRef._root.focus()

SherylHohman
  • 16,580
  • 17
  • 88
  • 94
Wishmaster
  • 1,102
  • 14
  • 20
9

My scenario is < CustomBoladonesTextInput /> wrapping a RN < TextInput />.

I solved this issue as follow:

My form looks like:

  <CustomBoladonesTextInput 
      onSubmitEditing={() => this.customInput2.refs.innerTextInput2.focus()}
      returnKeyType="next"
      ... />

  <CustomBoladonesTextInput 
       ref={ref => this.customInput2 = ref}
       refInner="innerTextInput2"
       ... />

On CustomBoladonesTextInput's component definition, I pass the refField to the inner ref prop like this:

   export default class CustomBoladonesTextInput extends React.Component {
      render() {        
         return (< TextInput ref={this.props.refInner} ... />);     
      } 
   }

And voila. Everything get back works again. Hope this helps

rodrix
  • 470
  • 6
  • 17
8

If you happen to be using tcomb-form-native as I am, you can do this, too. Here's the trick: instead of setting the props of the TextInput directly, you do it via options. You can refer to the fields of the form as:

this.refs.form.getComponent('password').refs.input.focus()

So the final product looks something like this:

var t = require('tcomb-form-native');
var Form = t.form.Form;

var MyForm = t.struct({
  field1:     t.String,
  field2:     t.String,
});

var MyComponent = React.createClass({

  _getFormOptions () {
    return {
      fields: {
        field1: {
          returnKeyType: 'next',
          onSubmitEditing: () => {this.refs.form.getComponent('field2').refs.input.focus()},
        },
      },
    };
  },

  render () {

    var formOptions = this._getFormOptions();

    return (
      <View style={styles.container}>
        <Form ref="form" type={MyForm} options={formOptions}/>
      </View>
    );
  },
});

(Credit to remcoanker for posting the idea here: https://github.com/gcanti/tcomb-form-native/issues/96)

Lane Rettig
  • 6,640
  • 5
  • 42
  • 51
  • how do I call function onSubmitEditing ? for ex: I want to call login() function when user press last textinput's returnkeytype 'done'. – chetan Dec 14 '17 at 11:22
8

This is the way I achieved it. And the example below has used the React.createRef() API introduced in React 16.3.

class Test extends React.Component {
  constructor(props) {
    super(props);
    this.secondTextInputRef = React.createRef();
  }

  render() {
    return(
        <View>
            <TextInput
                placeholder = "FirstTextInput"
                returnKeyType="next"
                onSubmitEditing={() => { this.secondTextInputRef.current.focus(); }}
            />
            <TextInput
                ref={this.secondTextInputRef}
                placeholder = "secondTextInput"
            />
        </View>
    );
  }
}

I think this will help you.

Janaka Pushpakumara
  • 4,769
  • 5
  • 29
  • 34
6

Try this solution on React Native's GitHub issues.

https://github.com/facebook/react-native/pull/2149#issuecomment-129262565

You need to use the ref prop for the TextInput component.
Then you need a create a function that gets called on onSubmitEditing prop that moves the focus on the second TextInput ref.

var InputScreen = React.createClass({
    _focusNextField(nextField) {
        this.refs[nextField].focus()
    },

    render: function() {
        return (
            <View style={styles.container}>
                <TextInput
                    ref='1'
                    style={styles.input}
                    placeholder='Normal'
                    returnKeyType='next'
                    blurOnSubmit={false}
                    onSubmitEditing={() => this._focusNextField('2')}
                />
                <TextInput
                    ref='2'
                    style={styles.input}
                    keyboardType='email-address'
                    placeholder='Email Address'
                    returnKeyType='next'
                    blurOnSubmit={false}
                    onSubmitEditing={() => this._focusNextField('3')}
                />
                <TextInput
                    ref='3'
                    style={styles.input}
                    keyboardType='url'
                    placeholder='URL'
                    returnKeyType='next'
                    blurOnSubmit={false}
                    onSubmitEditing={() => this._focusNextField('4')}
                />
                <TextInput
                    ref='4'
                    style={styles.input}
                    keyboardType='numeric'
                    placeholder='Numeric'
                    blurOnSubmit={false}
                    onSubmitEditing={() => this._focusNextField('5')}
                />
                <TextInput
                    ref='5'
                    style={styles.input}
                    keyboardType='numbers-and-punctuation'
                    placeholder='Numbers & Punctuation'
                    returnKeyType='done'
                />
            </View>
        );
    }
});
APAquino
  • 71
  • 3
  • Please include the relative information from the link in your answer. – Wes Foster Sep 24 '15 at 04:27
  • 1
    Keep in mind that string refs may become deprecated so this solution may not work in the future: "...Although string refs are not deprecated, they are considered legacy, and will likely be deprecated at some point in the future. Callback refs are preferred." -- https://facebook.github.io/react/docs/more-about-refs.html – yura Aug 09 '16 at 21:05
  • 1
    This doesn't work anymore, as of v0.36. There is no method "focus" on the component. How should we do this now? Can you update the answer? – Mitch Nov 01 '16 at 05:57
  • @Mitch not sure if this is back on 0.39.2 but this works fine now. – Eldelshell Dec 17 '16 at 18:41
5
<TextInput placeholder="Nombre"
    ref="1"
    editable={true}
    returnKeyType="next"
    underlineColorAndroid={'#4DB6AC'}
    blurOnSubmit={false}
    value={this.state.First_Name}
    onChangeText={First_Name => this.setState({ First_Name })}
    onSubmitEditing={() => this.focusNextField('2')}
    placeholderTextColor="#797a7a" style={{ marginBottom: 10, color: '#808080', fontSize: 15, width: '100%', }} />

<TextInput placeholder="Apellido"
    ref="2"
    editable={true}
    returnKeyType="next"
    underlineColorAndroid={'#4DB6AC'}
    blurOnSubmit={false}
    value={this.state.Last_Name}
    onChangeText={Last_Name => this.setState({ Last_Name })}
    onSubmitEditing={() => this.focusNextField('3')}
    placeholderTextColor="#797a7a" style={{ marginBottom: 10, color: '#808080', fontSize: 15, width: '100%', }} />

and add method

focusNextField(nextField) {
    this.refs[nextField].focus();
}
stasiaks
  • 1,268
  • 2
  • 14
  • 31
Saloni Parikh
  • 144
  • 1
  • 10
  • 2
    Old answer but does anyone know if it's possible to access all refs like in this answer in a functional (stateless) component? – Douglas Schmidt Dec 04 '19 at 19:30
4

Using callback refs instead of the legacy string refs:

<TextInput
    style = {styles.titleInput}
    returnKeyType = {"next"}
    autoFocus = {true}
    placeholder = "Title"
    onSubmitEditing={() => {this.nextInput.focus()}}
/>
<TextInput
    style = {styles.descriptionInput}  
    multiline = {true}
    maxLength = {200}
    placeholder = "Description"
    ref={nextInput => this.nextInput = nextInput}
/>
fagerbua
  • 406
  • 2
  • 9
2

For the accepted solution to work if your TextInput is inside another component, you'll need to "pop" the reference from ref to the parent container.

// MyComponent
render() {
    <View>
        <TextInput ref={(r) => this.props.onRef(r)} { ...this.props }/>
    </View>
}

// MyView
render() {
    <MyComponent onSubmitEditing={(evt) => this.myField2.focus()}/>
    <MyComponent onRef={(r) => this.myField2 = r}/>
}
Eldelshell
  • 6,683
  • 7
  • 44
  • 63
2

in your component:

constructor(props) {
        super(props);
        this.focusNextField = this
            .focusNextField
            .bind(this);
        // to store our input refs
        this.inputs = {};
    }
    focusNextField(id) {
        console.log("focus next input: " + id);
        this
            .inputs[id]
            ._root
            .focus();
    }

Note: I used ._root because it is a ref to TextInput in NativeBase'Library' Input

and in your text inputs like this

<TextInput
         onSubmitEditing={() => {
                          this.focusNextField('two');
                          }}
         returnKeyType="next"
         blurOnSubmit={false}/>


<TextInput      
         ref={input => {
              this.inputs['two'] = input;
                        }}/>
amorenew
  • 10,760
  • 10
  • 47
  • 69
2
<TextInput 
    keyboardType="email-address"
    placeholder="Email"
    returnKeyType="next"
    ref="email"
    onSubmitEditing={() => this.focusTextInput(this.refs.password)}
    blurOnSubmit={false}
 />
<TextInput
    ref="password"
    placeholder="Password" 
    secureTextEntry={true} />

And add method for onSubmitEditing={() => this.focusTextInput(this.refs.password)} as below:

private focusTextInput(node: any) {
    node.focus();
}
Nisar
  • 828
  • 1
  • 10
  • 28
2

Here is how achieved this for reactjs phone code inputs

import React, { useState, useRef } from 'react';

function Header(props) {

  const [state , setState] = useState({
        phone_number:"",
        code_one:'',
        code_two:'',
        code_three:'',
        code_four:'',
        submitted:false,

  })

   const codeOneInput = useRef(null);
   const codeTwoInput = useRef(null);
   const codeThreeInput = useRef(null);
   const codeFourInput = useRef(null);

   const handleCodeChange = (e) => {
        const {id , value} = e.target
        if(value.length < 2){
            setState(prevState => ({
                ...prevState,
                [id] : value
            }))
            if(id=='code_one' && value.length >0){
                codeTwoInput.current.focus();
            }
            if(id=='code_two'  && value.length >0){
                codeThreeInput.current.focus();
            }
            if(id=='code_three'  && value.length >0){
                codeFourInput.current.focus();
            }
        }
    }

    const sendCodeToServer = () => {

         setState(prevState => ({
                ...prevState,
                submitted : true,
          }))
  let codeEnteredByUser = state.code_one + state.code_two + state.code_three + state.code_four

        axios.post(API_BASE_URL, {code:codeEnteredByUser})
        .then(function (response) {
            console.log(response)
        })

   }

   return(
        <>

           <div className="are">
                 <div className="POP-INN-INPUT">
                                        <input type="text" id="code_one" ref={codeOneInput}    value={state.code_one}  onChange={handleCodeChange} autoFocus/>
                                        <input type="text" id="code_two"  ref={codeTwoInput}  value={state.code_two} onChange={handleCodeChange}/>
                                        <input type="text" id="code_three"  ref={codeThreeInput} value={state.code_three}  onChange={handleCodeChange}/>
                                        <input type="text" id="code_four" ref={codeFourInput}  value={state.code_four}  onChange={handleCodeChange}/>
                                    </div>

            <button disabled={state.submitted} onClick={sendCodeToServer}>
   
    </div>

       </>
    )
}
export default

enter image description here

Muhammad Shahzad
  • 9,340
  • 21
  • 86
  • 130
1

There is a way to capture tabs in a TextInput. It's hacky, but better than nothing.

Define an onChangeText handler that compares the new input value with the old, checking for a \t. If one is found, advance the field as shown by @boredgames

Assuming the variable username contains the value for the username and setUsername dispatches an action to change it in the store (component state, redux store, etc), do something like this:

function tabGuard (newValue, oldValue, callback, nextCallback) {
  if (newValue.indexOf('\t') >= 0 && oldValue.indexOf('\t') === -1) {
    callback(oldValue)
    nextCallback()
  } else {
    callback(newValue)
  }
}

class LoginScene {
  focusNextField = (nextField) => {
    this.refs[nextField].focus()
  }

  focusOnPassword = () => {
    this.focusNextField('password')
  }

  handleUsernameChange = (newValue) => {
    const { username } = this.props            // or from wherever
    const { setUsername } = this.props.actions // or from wherever

    tabGuard(newValue, username, setUsername, this.focusOnPassword)
  }

  render () {
    const { username } = this.props

    return (
      <TextInput ref='username'
                 placeholder='Username'
                 autoCapitalize='none'
                 autoCorrect={false}
                 autoFocus
                 keyboardType='email-address'
                 onChangeText={handleUsernameChange}
                 blurOnSubmit={false}
                 onSubmitEditing={focusOnPassword}
                 value={username} />
    )
  }
}
marius
  • 41
  • 3
  • This didn't work for me using a physical keyboard. the onChangeText event doesn't fire on tab. – Bufke Dec 21 '16 at 22:35
1

Really annoying that RN doesn't have some sort of Tabindex system.

A functional component, for my use case, I have an array of string IDs for inputs which I iterate through and show one text input each. The following code will automatically jump the user through all of them, stopping the keyboard from disappearing/reappearing between fields and dismissing it at the end, also showing the appropriate "action" button on the keyboard.

Typescript, Native Base.

const stringFieldIDs = [
  'q1', 'q2', 'q3'
];

export default () => {
  const stringFieldRefs = stringFieldIDs.map(() => useRef < any > ());

  const basicStringField = (id: string, ind: number) => {
    const posInd = stringFieldIDs.indexOf(id);
    const isLast = posInd === stringFieldIDs.length - 1;

    return ( <
      Input blurOnSubmit = {
        isLast
      }
      ref = {
        stringFieldRefs[posInd]
      }
      returnKeyType = {
        isLast ? 'done' : 'next'
      }
      onSubmitEditing = {
        isLast ?
        undefined :
          () => stringFieldRefs[posInd + 1].current._root.focus()
      }
      />
    );
  };

  return stringFieldIDs.map(basicStringField);
};
user37309
  • 597
  • 5
  • 14
1
import React, { useState, useEffect, useRef, } from 'react';

const OTP = (props) => {



    const OTP = [];
    const ref_input = [];
    ref_input[0] = useRef();
    ref_input[1] = useRef();
    ref_input[2] = useRef();
    ref_input[3] = useRef();

    const focusNext = (text, index) => {
        if (index < ref_input.length - 1 && text) {
            ref_input[index + 1].current.focus();
        }
        if (index == ref_input.length - 1) {
            ref_input[index].current.blur();
        }
        OTP[index] = text;
    }
    const focusPrev = (key, index) => {
        if (key === "Backspace" && index !== 0) {
            ref_input[index - 1].current.focus();
        }
    }

    return (
        <SafeAreaView>
            <View>
                
                    <ScrollView contentInsetAdjustmentBehavior="automatic" showsVerticalScrollIndicator={false}>
                        <View style={loginScreenStyle.titleWrap}>
                            <Title style={loginScreenStyle.titleHeading}>Verify OTP</Title>
                            <Subheading style={loginScreenStyle.subTitle}>Enter the 4 digit code sent to your mobile number</Subheading>
                        </View>
                        <View style={loginScreenStyle.inputContainer}>
                            <TextInput
                                mode="flat"
                                selectionColor={Colors.primaryColor}
                                underlineColorAndroid="transparent"
                                textAlign='center'
                                maxLength={1}
                                keyboardType='numeric'
                                style={formScreenStyle.otpInputStyle}
                                autoFocus={true}
                                returnKeyType="next"
                                ref={ref_input[0]}
                                onChangeText={text => focusNext(text, 0)}
                                onKeyPress={e => focusPrev(e.nativeEvent.key, 0)}
                            />
                            <TextInput
                                mode="flat"
                                selectionColor={Colors.primaryColor}
                                underlineColorAndroid="transparent"
                                textAlign='center'
                                maxLength={1}
                                keyboardType='numeric'
                                style={formScreenStyle.otpInputStyle}
                                ref={ref_input[1]}
                                onChangeText={text => focusNext(text, 1)}
                                onKeyPress={e => focusPrev(e.nativeEvent.key, 1)}
                            />
                            <TextInput
                                mode="flat"
                                selectionColor={Colors.primaryColor}
                                underlineColorAndroid="transparent"
                                textAlign='center'
                                maxLength={1}
                                keyboardType='numeric'
                                style={formScreenStyle.otpInputStyle}
                                ref={ref_input[2]}
                                onChangeText={text => focusNext(text, 2)}
                                onKeyPress={e => focusPrev(e.nativeEvent.key, 2)}
                            />
                            <TextInput
                                mode="flat"
                                selectionColor={Colors.primaryColor}
                                underlineColorAndroid="transparent"
                                textAlign='center'
                                maxLength={1}
                                keyboardType='numeric'
                                style={formScreenStyle.otpInputStyle}
                                ref={ref_input[3]}
                                onChangeText={text => focusNext(text, 3)}
                                onKeyPress={e => focusPrev(e.nativeEvent.key, 3)}
                            />

                        </View>
                    </ScrollView>
            </View>
        </SafeAreaView >
    )
}

export default OTP;
Diego Jiménez
  • 1,398
  • 1
  • 15
  • 26
0

If you are using NativeBase as UI Components you can use this sample

<Item floatingLabel>
    <Label>Title</Label>
    <Input
        returnKeyType = {"next"}
        autoFocus = {true}
        onSubmitEditing={(event) => {
            this._inputDesc._root.focus(); 
        }} />
</Item>
<Item floatingLabel>
    <Label>Description</Label>
    <Input
        getRef={(c) => this._inputDesc = c}
        multiline={true} style={{height: 100}} />
        onSubmitEditing={(event) => { this._inputLink._root.focus(); }} />
</Item>
stasiaks
  • 1,268
  • 2
  • 14
  • 31
0

onSubmitEditing is called when returnKeyType key is pressed. when you switch to next input, to prevent the flashing (in a fast system can be ignored) blurOnSubmit={false}

import React, { ReactElement, useRef, useState } from "react";
import {  ScrollView, TextInput as NativeTextInput, TouchableOpacity } from "react-native";

    
export default function LoginScreen({ navigation, route }: LoginProps): ReactElement {
    const passwordRef = useRef<NativeTextInput | null>(null);
    const [form, setForm] = useState({
        username: "player1",
        password: "player1234"
    });
    const setFormInput = (key: keyof typeof form, value: string) =>
        setForm({ ...form, [key]: value });

    return (
            <ScrollView contentContainerStyle={styles.container}>
                <TextInput
                    value={form.username}
                    onChangeText={value => setFormInput("username", value)}
                    returnKeyType="next"
                    blurOnSubmit={false}
                    placeholder="Username"
                    onSubmitEditing={() => {
                        passwordRef.current?.focus();
                    }}
                />
                <TextInput
                    value={form.password}
                    onChangeText={value => setFormInput("password", value)}
                    ref={passwordRef}
                    returnKeyType="done"
                    secureTextEntry
                    placeholder="Password"
                />
            </ScrollView>
    );
}
Yilmaz
  • 35,338
  • 10
  • 157
  • 202
-1

Here a reagent solution for a input component that has a :focus property.

The field will be focused as long as this prop is set to true and will not have focus as long as this is false.

Unfortunately this component needs to have a :ref defined, I could not find an other way to call .focus() on it. I am happy about suggestions.

(defn focusable-input [init-attrs]
  (r/create-class
    {:display-name "focusable-input"
     :component-will-receive-props
       (fn [this new-argv]
         (let [ref-c (aget this "refs" (:ref init-attrs))
               focus (:focus (ru/extract-props new-argv))
               is-focused (.isFocused ref-c)]
           (if focus
             (when-not is-focused (.focus ref-c))
             (when is-focused (.blur ref-c)))))
     :reagent-render
       (fn [attrs]
         (let [init-focus (:focus init-attrs)
               auto-focus (or (:auto-focus attrs) init-focus)
               attrs (assoc attrs :auto-focus auto-focus)]
           [input attrs]))}))

https://gist.github.com/Knotschi/6f97efe89681ac149113ddec4c396cc5

Knotschi
  • 109
  • 1
  • 6
  • @Bap - this is Clojurescript. Reagent is a binding to React. If you're curious, it's a great match for React if you are up for a lisp as stateful updates are generally only possible with things like an explicit call to `swap!` on an `atom` type. As per the docs, this is used for binding to React: "Any component that uses an atom is automagically re-rendered when its value changes." http://reagent-project.github.io/ – Del Apr 01 '19 at 17:29