The hidden Text Input of React Native apps
This my first take on looking for a straightforward unified solution to responding to Keyboard open–change–hide events in React Native. There are great solutions that work great in some specific cases. But I’ve tried and failed to get them work great together.
--
This is the first article to cover this broad topic to invite others to share their experience. I am sharing mine together with some code samples. I am looking for your comments and thoughts.
The new “average”
Look at the list of the most used apps in the app stores. Most people have had experience with most of them. Those apps provide some of the best, if not the top user experience on mobile. That’s what they, I mean we all expect the same from your app.
Specifically, we expect apps to:
- keep the content accessible while the keyboard is open;
- dismiss the keyboard interactively while scrolling down the the bottom edge of the screen;
- auto-scroll to the next input;
- safely avoid the front facing camera notches and other indicators;
- move floating text input above the keyboard when changing languages;
- and of course the buttery smooth animations.
We all want that to work seamlessly and all together.
And we want that in our apps too. People using our apps expect the same high–class experience as with apps with way more budget to have it.
Anything else is…well… less than average. But it all looks more like this…
Our solution needs to:
#1: Avoid the Keyboard
Solutions:
import { KeyboardAvoidingView } from 'react-native'
by the Core Team;import KeybardSpacer from 'react-native-keyboard-spacer'
by Andrew Hurst;
To make it a bit more complicated, on Android you can set the android:windowSoftInputMode
attribute to tell your your app (activity) how it should respond to Keyboard popping-out in the App’s manifest file.
Making iOS and Android play well together gets complicated if you want to…
#2: Avoid the device notches
Solutions:
import { SafeAreaView } from 'react-native'
by the Core Team;import SafeAreaView from 'react-native-safe-area-view'
by the React Native Community.
The Community version is just rolling new version that could support also the growing number of Android devices with obscured notches, home buttons by implementing React Native Safe Area Context library.
There are some (hard to replicate) edge cases where the SafeAreaView
fails to restore the safe padding or, on the other hand fails to remove padding after it stops touching the edge.
Implementation of the above two behaves differently. The community version works mostly more reliable.
Problem #3: Using with ScrollView, solutions:
import { KeyboardAwareScrollView } from 'react-native-keyboard-aware-scroll-view'
from APSL to automatically adjustScrollView
and scroll to recently focusedTextInput
when the Keyboard opens.
~ How to implement withSafeAreaView
(and which) is questionable.- You try to implement it yourself using
import { SafeAreaView, KeyboardAvoidingView, ScrollView } from 'react-native'
.
Solution(s)
TL;DR: Below solutions might work for some cases–at best 80/20 solutions.
First version: Naive
Wish this would work out-of-the-box.
Pros:
- initial scroll-to the focused field for free; Keyboard size changes do not handle
TextInput
being obscured by the keyboard; - uses just the core components;
- simple with minimum boilerplate;
- quite similar behavior with Android with
android:windowSofInputMode="adjustResize"
set in the manifest;
Cons:
- fails to scroll to focused input correctly with React Navigation’s header present;
- core
SafeAreaView
inScrollView
“collapses” after the Keyboard closes; - padding of the
KeyboardAvoidingView
obscures the view whenScrollView
’skeyboardDismissMode
is set tointeractive
.
But we can do better than…
Version 2: Keep Safe Area View active
Just by swapping the core SafeAreaView
with the Community version, it won’t collapse after closing the keyboard.
Cons:
- Safe area stays active when keyboard is open and keeps extra padding all the time.
The keyboard interactive dismiss mode still fails to work… but this is kind of… better. (I guess.)
Version 3: Automatic scroll to with Header
If the distance between the top of the screen and the react native view is non-zero (e.g. Header from React Navigation), the Screen container fails to scroll to the input correctly.
If you don’t need the header, the failing scroll to focused input can be overcome by navigationOptions: { header: null }
on screen component. That removes the header crated by React Navigation.
But in most cases, you need to keep the header.
Let’s measure the position of the container and pass the keyboardVerticalOffset to the KeyboardAvoidingView
.
There are still few things we might want to improve, but in most cases this solution should work quite decently.
To be continued…
What still needs to be solved:
- Interoperability with Android;
- Disable
SafeAreaView
when Keyboard is open, reactive on close; - Scroll-to the next focused input;
- Adapt to Keyboard size change;
- Dismiss keyboard on fast scroll, keep open on slow scroll;
- Interactive keyboard dismissal on iOS (mostly a nice to have);
- … something else I haven’t thought of.
Leave your comment below. I’m looking forward to what you find out.