Update: Thanks to hooks, it's now much easier to dismiss the keyboard in standard view. Learn how here.

When using a View in React Native, you don't have any control over the keyboard. So, if the view has an input field and the user taps away from the input field, the keyboard will remain visible. The user has no way to get rid of the keyboard.

Sample Code:

<SafeAreaView>
  <View>

    <TextInput
      autoCapitalize="none"
      keyboardType="email-address"
      onChangeText={ this.changeEmailText }
      placeholder="Email Address"
      style={ [styles.textInput, emailInvalid ? styles.textInputError : null] }
      testID="email"
      value={ email }
    />

    <TextInput
      onChangeText={ this.changePasswordText }
      placeholder="Password"
      secureTextEntry
      style={ [styles.textInput, passwordInvalid ? styles.textInputError : null] }
      testID="password"
      value={ password }
    />

    <Text>
      { failureMessage }
    </Text>

    { !loggingIn
      && (
        <Button
          onPress={ this.login }
          testID="button-login"
          title="Login"
          color="#841584"
          accessibilityLabel="Login"
        />
      )
    }

    <Button
      onPress={ this.closeModal }
      testID="button-close-modal"
      title="Close"
      color="#841584"
      accessibilityLabel="Close"
    />

  </View>
</SafeAreaView>

Trying to dismiss the keyboard:

Dismissing the keyboard with a ScrollView

Some people suggest replacing the View with a ScrollView as it has keyboard dismissing ability built-in. By default, tapping outside of an input on a ScrollView will automatically dismiss the keyboard. Adding keyboardDismissMode="on-drag" will also allow the keyboard to dismiss if the view is dragged. Nice!

Sample Code

<SafeAreaView>
  <ScrollView
    keyboardDismissMode="on-drag"
    style={ styles.view }
  >

    <TextInput
      autoCapitalize="none"
      keyboardType="email-address"
      onChangeText={ this.changeEmailText }
      placeholder="Email Address"
      style={ [styles.textInput, emailInvalid ? styles.textInputError : null] }
      testID="email"
      value={ email }
    />

    <TextInput
      onChangeText={ this.changePasswordText }
      placeholder="Password"
      secureTextEntry
      style={ [styles.textInput, passwordInvalid ? styles.textInputError : null] }
      testID="password"
      value={ password }
    />

    <Text>
      { failureMessage }
    </Text>

    { !loggingIn
      && (
        <Button
          onPress={ this.login }
          testID="button-login"
          title="Login"
          color="#841584"
          accessibilityLabel="Login"
        />
      )
    }

    <Button
      onPress={ this.closeModal }
      testID="button-close-modal"
      title="Close"
      color="#841584"
      accessibilityLabel="Close"
    />

  </ScrollView>
</SafeAreaView>

Dismissing the keyboard with a ScrollView:

Teaching your View to dismiss the keyboard

However, in many cases, you don't want to or can't use a ScrollView. In these instances, you can achieve the same effect while still using a View. You just have to tell the view to deal with taps that aren't handled by any children. The onStartShouldSetResponder and onResponderRelease View properties are needed to teach your View to handle taps that aren't handled by child components.

Sample Code:

// Be sure to import the Keyboard
import { Keyboard } from 'react-native'

// Tell the view what to do with taps
const shouldSetResponse = () => true;
const onRelease = () => (
  Keyboard.dismiss()
);

// Your view
<SafeAreaView>
  <View
    onResponderRelease={ onRelease }
    onStartShouldSetResponder={ shouldSetResponse }
    style={ { height: '100%' } }
  >

    <TextInput
      autoCapitalize="none"
      keyboardType="email-address"
      onChangeText={ this.changeEmailText }
      placeholder="Email Address"
      style={ [styles.textInput, emailInvalid ? styles.textInputError : null] }
      testID="email"
      value={ email }
    />

    <TextInput
      onChangeText={ this.changePasswordText }
      placeholder="Password"
      secureTextEntry
      style={ [styles.textInput, passwordInvalid ? styles.textInputError : null] }
      testID="password"
      value={ password }
    />

    <Text>
      { failureMessage }
    </Text>

    { !loggingIn
      && (
        <Button
          onPress={ this.login }
          testID="button-login"
          title="Login"
          color="#841584"
          accessibilityLabel="Login"
        />
      )
    }

    <Button
      onPress={ this.closeModal }
      testID="button-close-modal"
      title="Close"
      color="#841584"
      accessibilityLabel="Close"
    />

  </View>
</SafeAreaView>

NOTE : Notice the style={ { height: '100%' } } on the new view with responders? This is necessary so that the view takes up the whole screen. Otherwise, it will only be as tall as the form and not detect any taps outside the form.

Dismissing the keyboard with a tap aware View: