When you create an application, you need to manage the keyboard and in theory, the principle is quite simple. When you press an input, the keyboard opens and when you press outside the input the keyboard closes. But this behavior is not trivial in React-Native and you will have to handle it by yourself.
I will distinguish between two types of screens here, screens wrapped with a ++code>View
++/code> and a ++code>ScrollView
.++/code>
If your screen is wrapped with a ++code>View
++/code>, you can see below that the keyboard does not close automatically when you press outside your input.
If your screen is wrapped with a ++/code>ScrollView
++/code>, we have 3 different behaviors depending on the prop ++code>keyboardShouldPersistTaps
++/code> and according to ++code>ScrollView
++/code> documentation :
What is missing here? It is impossible to handle button press and dismiss the keyboard with a single click. With ++code>never
++/code>, need one press to dismiss the keyboard and another to handle the button. With ++code>always
++/code>, we simply cannot close the keyboard and with ++code>handled
++/code>, pressing the button does not dismiss the keyboard.
I first checked on the internet to see what the current solutions were and I found this : Wrapping your application with a Pressable that dismisses the keyboard. The ++code>Pressable
++/code> that dismiss the keyboard. The ++code>accessible={false}
++/code> is here to avoir breaking accessibility, you can check this article if you want to learn more.
This is very simple but is equivalent to the ++code>keyboardShouldPersistTaps="handled"
++/code> of the ++code>Scrollview
++/code>, when we press a child button the keyboard is not dismissed and this can lead to bugs.
For example, if you want to open a ++code>BottomSheet
++/code> when you click on a button by using ++code>presentation: "transparentModal"
++/code> of ++code>react-navigation
++/code> . You will have the following behavior on Android.
This is how it works:
Here we use react-native-gesture-handler to detect the tap and dismiss the keyboard even if a child (e.g. a button) catches it. Dismissing the keyboard at the end of the tap ensures that scrolling still works with the keyboard open. We also ensure that the keyboard is not dismissed when a ++code>TextInput
++/code> is pressed with a solution inspired by ++code>Scrollview
++/code>’s code using ++code>isTextInput(e.target)
++/code>. When a ++code>TextInput
++/code> is mounted, it reference is added to a ++code>Set
++/code> and ++code>isTextInput
++/code> simply checks if the inputs ++code>Set
++/code> contains the target.
⚠️ Warning
GestureHandlerRootView
++/code>KeyboardDismissPressable
++/code> instead of wrapping the whole application to avoid some conflicts and to be more flexible if some pages need a different behavior.TextInputState
++/code> because this state is not exposed by react-native. So this internal function may be changed in future versions of react-native.I am open to your challenges or ideas to improve this component so feel free to contact me if you would like to discuss this topic.