64

I'm building an Android app with React Native.

How can you force a TextInput to "unFocus", meaning the cursor is blinking inside the text field. There are functions for isFocused() and onFocus(), but how do I actually get the text field to give up focus. You would think it does so automatically once I hit enter, but that's not the case.

   import React, {Component} from 'react';
   import { AppRegistry, Text, View, StyleSheet, TextInput, TouchableOpacity} 
   from 'react-native';

   var SHA256 = require("crypto-js/sha256");

   export default class LoginForm extends Component{


constructor(props){
    super(props);
    this.state = {
        email: '',
        password:''
    };
}

tryLogin = () => {
    if(this.state.email=="email123" && this.state.password == "password"){
        console.log("password verified");
        this.props.navigator.replace({
            title: 'Dashboard'
        });
    }

    console.log(this.state.email);
    console.log(this.state.password);
    console.log("Hash" + SHA256(this.state.password));
}

render(){
    return(
        <View style={styles.container}>
            <TextInput 
                style={styles.input}

                placeholder="Email address" 
                placeholderTextColor="white"
                onChangeText={(email) => this.setState({email})}>
            </TextInput>
            <TextInput style={styles.input} 
                placeholder="Password" 
                placeholderTextColor="white" 
                secureTextEntry
                onChangeText={(password) => this.setState({password})}>
            </TextInput>

            <TouchableOpacity style={styles.loginButtonContainer} onPress={this.tryLogin}>
                <Text style={styles.loginButtonText}>LOGIN</Text>
            </TouchableOpacity>
        </View>
  );
}
}

AppRegistry.registerComponent('LoginForm', () => LoginForm);

const styles =  StyleSheet.create({
container: {
    padding: 20
},
input:{
    height: 40,
    backgroundColor: '#e74c3c',
    marginBottom: 20,
    color: 'white',
    paddingHorizontal: 15,
    opacity: .9
},
loginButtonContainer:{
    justifyContent: 'center',
    backgroundColor: '#bc4c3c',
    paddingVertical:15

},
loginButtonText:{
    textAlign:'center',
    color:'white',
    fontWeight: '700',
    fontSize: 24

}

   })

This probably won't matter as much for real users but I'm just emulating and its pesky if I want to reload.

Ahmer Afzal
  • 501
  • 2
  • 11
  • 24
Noah Mendoza
  • 777
  • 1
  • 7
  • 17
  • Just using a hash function is not sufficient and just adding a salt does little to improve the security. Instead iIterate over an HMAC with a random salt for about a 100ms duration and save the salt with the hash. Use a function such as `PBKDF2`, `Rfc2898DeriveBytes`, `password_hash`, `Bcrypt` or similar functions. The point is to make the attacker spend a lot of time finding passwords by brute force. – zaph Apr 16 '17 at 01:20
  • Possible duplicate of [Hide keyboard in react-native](https://stackoverflow.com/questions/29685421/hide-keyboard-in-react-native) – dǝɥɔS ʇoıןןƎ Sep 07 '18 at 20:42

10 Answers10

73

A better way is to use ScrollView and Keyboard.dismiss. By using ScrollView when the user taps outside of textInput, keyboard dismissed. It's done because ScrollView default property for keyboardShouldPersistTaps is never. It's the behavior the user expects. For dismiss the keyboard, or it's equivalent blur the textInput, when the user tap on the login button add Keyboard.dismissed() to the tryLogin function.

import React, {Component} from 'react';
import { AppRegistry, Text, View, StyleSheet, TextInput, TouchableOpacity, ScrollView, Keyboard}
  from 'react-native';
var SHA256 = require("crypto-js/sha256");

export default class LoginForm extends Component{


  constructor(props){
    super(props);
    this.state = {
      email: '',
      password:''
    };
  }

  tryLogin = () => {
    Keyboard.dismiss();
    if(this.state.email=="email123" && this.state.password == "password"){
      console.log("password verified");
      this.props.navigator.replace({
        title: 'Dashboard'
      });
    }

    console.log(this.state.email);
    console.log(this.state.password);
    console.log("Hash" + SHA256(this.state.password));
  }

  render(){
    return(
      <ScrollView style={styles.container}>
        <TextInput
          style={styles.input}

          placeholder="Email address"
          placeholderTextColor="white"
          onChangeText={(email) => this.setState({email})}>
        </TextInput>
        <TextInput style={styles.input}
                   placeholder="Password"
                   placeholderTextColor="white"
                   secureTextEntry
                   onChangeText={(password) => this.setState({password})}>
        </TextInput>

        <TouchableOpacity style={styles.loginButtonContainer} onPress={this.tryLogin}>
          <Text style={styles.loginButtonText}>LOGIN</Text>
        </TouchableOpacity>
      </ScrollView>
    );
  }
}

AppRegistry.registerComponent('LoginForm', () => LoginForm);

const styles =  StyleSheet.create({
  container: {
    padding: 20
  },
  input:{
    height: 40,
    backgroundColor: '#e74c3c',
    marginBottom: 20,
    color: 'white',
    paddingHorizontal: 15,
    opacity: .9
  },
  loginButtonContainer:{
    justifyContent: 'center',
    backgroundColor: '#bc4c3c',
    paddingVertical:15

  },
  loginButtonText:{
    textAlign:'center',
    color:'white',
    fontWeight: '700',
    fontSize: 24

  }

})
Meysam Izadmehr
  • 3,103
  • 17
  • 25
  • 1
    This works, what if the submit button and textinput is present on different component ? what do you propose in that case ? – Vasanth Aug 18 '22 at 07:37
42

You can use Keyboard API.

import { Keyboard, TextInput } from 'react-native';

<TextInput
  onSubmitEditing={Keyboard.dismiss}
/>

Please see the full example in react native offical document.

F. Huang
  • 429
  • 3
  • 3
15

I managed to solve this with this.ref reference. First, you assign to the TextInput a ref, like this:

<input ref="myInput" />

Then, you call the blur() method to this.refs.myInput from a function

 blurTextInput(){
    this.refs.myInput.blur()
 }
Make-HCI
  • 189
  • 3
  • 10
Adrian
  • 171
  • 1
  • 8
  • 1
    ref="myInput" got deprecated. Instead use ref={(ref) => { this.myInput= ref }} and use as this.myInput.focus() or this.myInput.blur() – Prantik Mondal Mar 02 '21 at 12:44
12

My use case was a little different. The user wouldn't enter a value directly in the input field. The field was mainly used to capture the user's attempt at entering a value and open a modal instead. I wanted to blur the field after the modal closed to reduce the extra tap the user would have to do later.

If using Hooks, you can do something as simple as

const inputRef = useRef(null);

<Input
  ref={inputRef}
  {...props}
/>

Then just call this anywhere you need it.

inputRef.current.blur();
Keno
  • 2,018
  • 1
  • 16
  • 26
  • 2
    This answer saved my day. Thanks – Buwaneka Sudheera Jul 07 '21 at 17:03
  • same case me. i recognize better wayt what Text Component set editable false And Text component wrap by View Or Touchable Component – Sacru2red Jul 29 '21 at 08:53
  • This works but what if textInput is in one component and button is in another component ? passing same reference to both by parent is not working ? any help ? – Vasanth Aug 18 '22 at 07:30
  • @Vasanth technically the reference method should work regardless unless the reference is outdated at the time of being called. Have you checked to ensure that the reference is still there when you're trying to blur it? – Keno Sep 27 '22 at 22:01
8

Found it actually.It doesn't look as pretty and my intuition says this isn't a very "react" solution but if you want it here it is.

<TextInput 
 style={styles.input} 
 ref="email_input"
 onSubmitEditing={() => this.refs['email_input'].blur()} 
 placeholder="Email address" 
 placeholderTextColor="white"
 onChangeText={(email) => this.setState({email})}/>
Noah Mendoza
  • 777
  • 1
  • 7
  • 17
1

It does what it needs

function TextInputCustom({ placeholder, style }) {

    React.useEffect(() => {
        const keyboardHide = Keyboard.addListener('keyboardDidHide', () => {
            Keyboard.dismiss();
        });
        return () => {
            keyboardHide.remove()
        }
    }, []);
    return (
        <TextInput
            style={style}
            placeholder={placeholder}            
        />
    )
}

export default TextInputCustom;
Peter Csala
  • 17,736
  • 16
  • 35
  • 75
  • As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Feb 20 '22 at 06:10
0

Noah's answer above works well, but using string refs is now discouraged in React, and is likely going to be deprecated soon. Instead, you should use a callback function that gets called when the component you want to reference renders.

<TextInput 
  ref={(c: any) => {
    this.textInputRef = c;
  }}
  onSubmitEditing={() => this.textInputRef.blur()} 
/>

If you're using Flow, you can then specify the type of your ref by placing something like this outside of your render function:

textInputRef: ?TextInput;
bogan27
  • 124
  • 1
  • 12
0

If you want to lose focus after submiting, use blurOnSubmit property.

<TextInput 
   blurOnSubmit={true}
   //other props
/>
Darkleon
  • 13
  • 2
  • 4
  • hi Darkleon, Welcome to SO, please provide more detail to your answer and a practical example about how to do this. thanks – Abilogos Nov 18 '21 at 14:40
0

I used the below code and it worked perfect for me: i wrap all the view inside TouchableWithoutFeedback and onPress={() => {Keyboard.dismiss();}}

 import {View,TouchableWithoutFeedback,Keyboard,} from 'react-native';
 ......
<SafeAreaView>
  <ScrollView nestedScrollEnabled={true}>
    <TouchableWithoutFeedback
      onPress={() => {Keyboard.dismiss();}}>
      <View style={styles.container}>
      {/* ..... */}
      </View>
    </TouchableWithoutFeedback>
  </ScrollView>
</SafeAreaView>
0

I made Keyboard dismiss on outside tap like so

<View onTouchStart={()=>Keyboard.dismiss()} style={{flex: 1, width: "100%"}}>
        <KeyboardAvoidingView style={{flex: 1}}>
                <TextInput></TextInput>
        </KeyboardAvoidingView>
</View>