BS
BleepingSwift
Published on

> Different Ways to Dismiss the Keyboard in React Native

Authors
  • avatar
    Name
    Mick MacCallum
    Twitter
    @0x7fs

One of those small UX details that can make or break a mobile app is keyboard handling. Users expect to tap outside a text input and have the keyboard go away. React Native doesn't give you this behavior by default, so you need to implement it yourself.

There are a few different approaches depending on your UI structure and what feels most natural for your app.

Using Keyboard.dismiss()

The most direct way is calling Keyboard.dismiss() from the Keyboard API. This programmatically hides the keyboard regardless of what triggered it.

import { Keyboard, TextInput, Button, View } from 'react-native'

function SearchForm() {
  const handleSearch = () => {
    Keyboard.dismiss()
    // perform search...
  }

  return (
    <View>
      <TextInput placeholder="Search..." />
      <Button title="Search" onPress={handleSearch} />
    </View>
  )
}

This is useful when you have an explicit action that should close the keyboard, like submitting a form or pressing a button. You can call it from anywhere in your component tree since it's a static method.

Wrapping with Pressable or TouchableWithoutFeedback

For the "tap anywhere to dismiss" pattern, wrap your screen content in a touchable component that calls Keyboard.dismiss() when pressed.

import { Keyboard, Pressable, TextInput, StyleSheet } from 'react-native'

function LoginScreen() {
  return (
    <Pressable style={styles.container} onPress={Keyboard.dismiss}>
      <TextInput placeholder="Email" style={styles.input} />
      <TextInput placeholder="Password" secureTextEntry style={styles.input} />
    </Pressable>
  )
}

const styles = StyleSheet.create({
  container: { flex: 1, padding: 20 },
  input: { borderWidth: 1, borderColor: '#ccc', padding: 12, marginBottom: 16 },
})

TouchableWithoutFeedback works the same way but Pressable is the more modern API and gives you more flexibility if you later need press states. Either works fine for this use case.

One thing to watch out for: if your container doesn't fill the screen, taps in the empty space won't register. Make sure your wrapper has flex: 1 or otherwise fills the available space.

ScrollView's keyboardDismissMode

If your content is in a ScrollView, you get keyboard dismissal behavior for free with the keyboardDismissMode prop.

import { ScrollView, TextInput } from 'react-native'

function FormScreen() {
  return (
    <ScrollView keyboardDismissMode="on-drag">
      <TextInput placeholder="Name" />
      <TextInput placeholder="Email" />
      <TextInput placeholder="Message" multiline numberOfLines={4} />
    </ScrollView>
  )
}

The options are:

  • "none": the default, keyboard stays open while scrolling
  • "on-drag": keyboard dismisses when the user starts scrolling
  • "interactive": (iOS only) keyboard dismisses interactively with the scroll, like in iMessage where you can drag it down

The "interactive" mode feels great but only works on iOS. Android will fall back to "none", so if you're targeting both platforms you might want to use "on-drag" for consistency.

Handling keyboardShouldPersistTaps

Related to ScrollView behavior is keyboardShouldPersistTaps. This controls whether tapping inside the ScrollView should dismiss the keyboard or pass through to child components.

<ScrollView keyboardDismissMode="on-drag" keyboardShouldPersistTaps="handled">
  {/* form content */}
</ScrollView>

The values are:

  • "never": tapping outside the focused input dismisses the keyboard, and the tap isn't passed to children
  • "always": keyboard never dismisses from taps, they always go to children
  • "handled": keyboard dismisses unless the tap is handled by a child (like a button press)

For most forms, "handled" is what you want. It lets users tap buttons without having to dismiss the keyboard first, but tapping empty space still closes it.

TextInput's Built-in Props

TextInput itself has some props that affect keyboard behavior. The blurOnSubmit prop (true by default for single-line inputs) causes the keyboard to dismiss when the user presses return.

<TextInput
  placeholder="Username"
  returnKeyType="done"
  onSubmitEditing={() => {
    // handle submission
  }}
/>

For multiline inputs, blurOnSubmit defaults to false since return just adds a new line. If you want a "Done" button that submits and dismisses:

<TextInput multiline blurOnSubmit={true} returnKeyType="done" onSubmitEditing={handleSubmit} />

Keep in mind this changes the return key behavior, which might not be what users expect in a multiline context. Sometimes it's better to have a separate submit button for multiline inputs.

Creating a DismissKeyboard Component

If you find yourself wrapping screens repeatedly, extract it into a reusable component:

import { Keyboard, Pressable, StyleSheet, ViewStyle } from 'react-native'
import { ReactNode } from 'react'

interface Props {
  children: ReactNode
  style?: ViewStyle
}

export function DismissKeyboard({ children, style }: Props) {
  return (
    <Pressable style={[styles.container, style]} onPress={Keyboard.dismiss}>
      {children}
    </Pressable>
  )
}

const styles = StyleSheet.create({
  container: { flex: 1 },
})

Then use it as a screen wrapper:

function ProfileScreen() {
  return (
    <DismissKeyboard>
      <TextInput placeholder="Display name" />
      <TextInput placeholder="Bio" multiline />
    </DismissKeyboard>
  )
}

Choosing the Right Approach

Which method to use depends on your screen structure. If you have a ScrollView, use keyboardDismissMode since it's already there. For static forms without scrolling, the Pressable wrapper works well. And for specific actions like button presses or form submissions, call Keyboard.dismiss() directly.

Most apps end up using a combination. The goal is making keyboard dismissal feel natural enough that users don't have to think about it.

For more details on the Keyboard API, see the React Native documentation.

subscribe.sh

// Stay Updated

Get notified when I publish new tutorials on Swift, SwiftUI, and iOS development. No spam, unsubscribe anytime.

>

By subscribing, you agree to our Privacy Policy.