Multiline TextInput Auto-growing and Scrolling Behavior Issues with KeyboardAwareScrollView
Overview I've identified several inconsistencies in the TextInput component's auto-growing behavior when used with KeyboardAwareScrollView, affecting both iOS and Android platforms. These issues vary depending on prop configurations and component wrapping.
Detailed Findings
Base Case (No value/onChangeText props)
- TextInput doesn't auto-grow regardless of multiline prop
- Height only respects minHeight or height style properties
- Behavior consistent across iOS and Android
https://github.com/user-attachments/assets/2f822e38-a325-45b2-936d-64f700c7cbb6
With value and onChangeText props
- Height Behavior:
- Respects minHeight and auto-grows after reaching minimum
- Fixed height when explicitly set; no auto-growing beyond specified height
- Scrolling Issues:
-
Noticeable "jumpy" behavior when:
- Cursor reaches end of last line
- First character on new line triggers internal scroll
- Second character triggers height auto-grow and ScrollView adjustment
https://github.com/user-attachments/assets/dc777281-5c3a-44c6-800b-810d45170821
- Less noticeable when cursor is in middle of content
TextInput Wrapped in View
- Auto-growing works without value/onChangeText props
- Platform-specific differences:
- iOS: Minimal jumping, hardly noticeable
- Android: Jumping behavior persists, similar to non-wrapped version
https://github.com/user-attachments/assets/8de0311e-15d3-43eb-9d50-f7fd09d81f47
Comparison with React Native's ScrollView Native ScrollView demonstrates superior behavior:
- Consistent auto-growing without requiring value/onChangeText props
- Significantly reduced jumping compared to KeyboardAwareScrollView with View wrapper
https://github.com/user-attachments/assets/645eadd1-dc1a-40b3-be95-a53005e00254
Code Examples I've included three implementation scenarios to demonstrate these issues and one with react native ScrollView:
- Basic Implementation
<KeyboardAwareScrollView>
<TextInput
multiline
placeholder="TextInput"
placeholderTextColor="black"
style={styles.textInput}
/>
</KeyboardAwareScrollView>
- With Props
<KeyboardAwareScrollView>
<TextInput
multiline
value={value}
onChangeText={onChange}
placeholder="TextInput"
placeholderTextColor="black"
style={styles.textInput}
/>
</KeyboardAwareScrollView>
- With View Wrapper
<KeyboardAwareScrollView>
<View>
<TextInput
multiline
placeholder="TextInput"
placeholderTextColor="black"
style={styles.textInput}
/>
</View>
</KeyboardAwareScrollView>
- React Native ScrollView
<ScrollView>
<TextInput
multiline
placeholder="TextInput"
placeholderTextColor="black"
style={styles.textInput}
/>
</ScrollView>
Devices tested: Android:
- Physical: Redmi Note 10 Pro
- Emulator: Pixel_8_API_35
iOS:
- Physical: iPhone 15
Development Environment:
- Desktop OS: MacOS Sonoma
Environment:
- expo: "~52.0.28"
- expo: "~52.0.28"
- react-native: "0.76.6"
- react-native-keyboard-controller: "^1.16.1"
@NyoriK do you test new architecture or old?
@kirillzyusko Yes.
app.json:
{
"expo": {
"name": "multiline-app",
"slug": "multiline-app",
"version": "1.0.0",
"orientation": "portrait",
"icon": "./assets/images/icon.png",
"scheme": "myapp",
"userInterfaceStyle": "automatic",
"newArchEnabled": true,
"ios": {
"supportsTablet": true,
"bundleIdentifier": "com.knyoridev.multiline-app"
},
"android": {
"adaptiveIcon": {
"foregroundImage": "./assets/images/adaptive-icon.png",
"backgroundColor": "#ffffff"
},
"package": "com.knyoridev.multilineapp"
},
"web": {
"bundler": "metro",
"output": "static",
"favicon": "./assets/images/favicon.png"
},
"plugins": [
"expo-router",
[
"expo-splash-screen",
{
"image": "./assets/images/splash-icon.png",
"imageWidth": 200,
"resizeMode": "contain",
"backgroundColor": "#ffffff"
}
]
],
"experiments": {
"typedRoutes": true
}
}
}
@NyoriK would you mind to try this PR? And let me know if it fixes the problem for you?
In general it works, but the main downside is that it doesn't work on Android - I opened a PR in react-native. Let's see if it gets accepted/merged 👀
@kirillzyusko I've tested the PR, and can confirm it works as intended on iOS.
The behavior is now much closer to native ScrollView. There's still some minor jumpiness when typing at the end of the TextInput, but this appears to be the same as with native ScrollView and is expected due to the combination of TextInput's internal scroll and asynchronous height adjustments (as discussed in #708).
Looking forward to the Android fix once the React Native PR is merged. Thanks for working on this!
@kirillzyusko Just tested again on Android and can confirm - the fix doesn't work on Android. When typing reaches the keyboard area, the KeyboardAwareScrollView doesn't scroll up, and the content being typed goes underneath the keyboard. Will await the Android fix once the React Native PR is merged.
Just tested again on Android and can confirm - the fix doesn't work on Android. When typing reaches the keyboard area, the KeyboardAwareScrollView doesn't scroll up, and the content being typed goes underneath the keyboard. Will await the Android fix once the React Native PR is merged.
Yeah, an intermediate solution can be combining "additional view" approach on Android and using contentInset on iOS.
But it looks like PR has been merged in upstream, so maybe in RN 0.79 we'll get this prop available on Android 🙈
Hi, I'm experiencing the same problems as describe in the issue chain. I'm using RN 0.79.2 and r-n-keyboard-controller 1.17.1. I'm testing on iOS (device and simulator). Curious is there a workaround for now?
The testing code I'm using is pretty simple. I'm trying to have an automatically expanding TextInput and when it grows the scrolling behaviour jumps to the top, or doesn't scroll to the caret.
return (
<KeyboardAwareScrollView bottomOffset={50}>
<TextInput value={text} onChangeText={setText} multiline style={styles.textInput} textAlignVertical="top" />
</KeyboardAwareScrollView>
);
One of the last issues with this lifesaver of a library. Subscribing.