`KeyboardAvoidingView` do not keep input in view under Android 15 (target SDK 35)
Description
Under RN 0.77.1 and Android 15 with targetSdkVersion = 35, the KeyboardAvoidingView stopped working as expected.
In the video below, we can see that clicking on the input brings the keyboard and makes the input disappear under the keyboard. However, just using targetSdkVersion = 34 fixed the issue.
Something is problematic under Android 15 SDK 35 and the KeyboardAvoidingView component.
Steps to reproduce
- Create an RN 77 project
npx @react-native-community/cli init Rn77App --version 0.77.1 - Use an input wrapped in a
KeyboardAvoidingViewunder the scroll view of the example app - Make sure to use
targetSdkVersion = 35 - Click on the input
- The input disappears under the keyboard
- Expected: The input moves up and stays in view, like when using
targetSdkVersion = 34or under RN 76
React Native Version
0.77.1
Affected Platforms
Runtime - Android
Output of npx @react-native-community/cli info
System:
OS: macOS 15.3
CPU: (12) arm64 Apple M2 Pro
Memory: 1.65 GB / 32.00 GB
Shell:
version: "5.9"
path: /bin/zsh
Binaries:
Node:
version: 18.20.4
path: ~/.nvm/versions/node/v18.20.4/bin/node
Yarn:
version: 1.22.22
path: ~/.nvm/versions/node/v18.20.4/bin/yarn
npm:
version: 10.7.0
path: ~/.nvm/versions/node/v18.20.4/bin/npm
Watchman:
version: 2024.11.04.00
path: /opt/homebrew/bin/watchman
Managers:
CocoaPods:
version: 1.16.2
path: /Users/dprevost/.rbenv/shims/pod
SDKs:
iOS SDK:
Platforms:
- DriverKit 24.2
- iOS 18.2
- macOS 15.2
- tvOS 18.2
- visionOS 2.2
- watchOS 11.2
Android SDK: Not Found
IDEs:
Android Studio: 2024.2 AI-242.23726.103.2422.13016713
Xcode:
version: 16.2/16C5032a
path: /usr/bin/xcodebuild
Languages:
Java:
version: 17.0.13
path: /usr/bin/javac
Ruby:
version: 3.3.3
path: /Users/dprevost/.rbenv/shims/ruby
npmPackages:
"@react-native-community/cli":
installed: 15.0.1
wanted: 15.0.1
react:
installed: 18.3.1
wanted: 18.3.1
react-native:
installed: 0.77.1
wanted: 0.77.1
react-native-macos: Not Found
npmGlobalPackages:
"*react-native*": Not Found
Android:
hermesEnabled: true
newArchEnabled: true
iOS:
hermesEnabled: true
newArchEnabled: true
Stacktrace or Logs
None
Reproducer
https://github.com/dprevost-LMI/Rn77App
Screenshots and Videos
The below are from a physical Pixel 9
| Working case under RN 76 | Non-working case under RN 77 and SDK 35 |
|---|---|
|
https://github.com/user-attachments/assets/1463d622-c878-4291-8511-454abcc8b312 |
https://github.com/user-attachments/assets/1bc84f01-ecea-4ed4-b897-6a1bf378668f |
Facing same issue! Any solution or if anyone fixing it?
facing same issue
cc @alanleedev Could you briefly look into this one?
Sorry for the delayed update. I was able to repro the issue but didn't have much chance to look into it yet.
for me the issue was the react-native-safe-area-context library, i had recently updated from ^0.7.3 to 0.1.0.
once downgraded the issue was resolved
Facing the same issue.
https://github.com/software-mansion/react-native-screens/issues/1719 for me this helped. I created a patch for navigationBarColor so that it doesn't change how keyboard behave previously in the project. The reason it is related is because I have upgraded rn-screens, when upgrading to RN 0.77.0.
The ~repo~ reproducable project is not having react-native-screen so if your issue is related to it, I suggest entering a new ticket!
@dprevost-LMI, yes, sure! But this kind of bugs are hard to debug, so I guess people are coming firstly to ReactNative (myself included). But indeed I think the issue is not directly related to RN repo.
Since Android API 35, I've noticed that adjustResize is no longer sufficient on its own, as described in this article. As an alternative, I set the IME padding manually in Kotlin, like
ViewCompat.setOnApplyWindowInsetsListener(rootView) { _, insets ->
val innerPadding = insets.getInsets(
WindowInsetsCompat.Type.ime()
)
rootView.setPadding(
innerPadding.left,
innerPadding.top,
innerPadding.right,
innerPadding.bottom)
insets
}
Which worked fine. However, I think RN could perhaps handle this IME padding by default in KeyboardAvoidingView? I can make a PR if it's fine
I'm facing same issues, It's working in android 14 devices, but not working in android 15.
Please resolve fast this issues.
@cortinico @alanleedev Hi, any update on this? There’s a fix suggested in the comments that seems to work well. Would it be possible to get this implemented? Thanks!
@cortinico @alanleedev Hi, any update on this? There’s a fix suggested in the comments that seems to work well. Would it be possible to get this implemented? Thanks!
If someone could send a PR with the fix, we could look into it
Same problem here, not working in android 15
Any update to this issue?
For those using React Navigation (which I assume includes most of us), this approach might help resolve your KeyboardAvoidingView issues — especially on Android 15.
Do not wrap your individual components with <KeyboardAvoidingView>. Instead, wrap the entire <Tab.Navigator> with it.
Here’s what worked for me:
import { KeyboardAvoidingView, Platform } from 'react-native';
function TabNavigator() {
return (
<KeyboardAvoidingView
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
style={{ flex: 1 }}>
<Tab.Navigator
screenOptions={{
headerShown: false,
}}>
<Tab.Screen name="Tab" component={StackContainer} />
</Tab.Navigator>
</KeyboardAvoidingView>
);
}
"dependencies": {
"@react-navigation/elements": "2.4.2",
"@react-navigation/native": "^7.1.9",
"@react-navigation/native-stack": "^7.3.13",
}
Adding padding to bottom of the scrollview(only for android 15) on keyboard show/hide with keyboardAvoidingView(for android 14 and below) did the job for me.
import { useEffect, useState } from 'react';
import { Keyboard, Platform } from 'react-native';
export const useKeyboard = () => {
const [keyboardHeight, setKeyboardHeight] = useState(0);
useEffect(() => {
function onKeyboardDidShow(e) {
setKeyboardHeight(e.endCoordinates.height);
}
function onKeyboardDidHide() {
setKeyboardHeight(0);
}
const showSubscription = Keyboard.addListener(
'keyboardDidShow',
onKeyboardDidShow,
);
const hideSubscription = Keyboard.addListener(
'keyboardDidHide',
onKeyboardDidHide,
);
return () => {
showSubscription.remove();
hideSubscription.remove();
};
}, []);
if (Platform.Version <= 34) {
return 0;
}
return keyboardHeight;
};
@sookcha Thanks for sharing this fix. Since the RN team is asking for a PR, would you be able to open one with your solution?
The above suggested change works for me too. I had to make that change in MainActivity.kt
import android.os.Build
import android.view.View
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
override fun onCreate(savedInstanceState: Bundle?) {
RNBootSplash.init(this, R.style.BootTheme)
super.onCreate(null)
if (Build.VERSION.SDK_INT >= 35) {
val rootView = findViewById<View>(android.R.id.content)
ViewCompat.setOnApplyWindowInsetsListener(rootView) { _, insets ->
val innerPadding = insets.getInsets(WindowInsetsCompat.Type.ime())
rootView.setPadding(
innerPadding.left,
innerPadding.top,
innerPadding.right,
innerPadding.bottom
)
insets
}
}
}
If you are still facing this issue, check whether the screen is from a stack navigator. Make sure you have wrapped your stack navigator inside a KeyboardAvoidingView, like this:
<KeyboardAvoidingView>
<Stack.Navigator>...</Stack.Navigator>
</KeyboardAvoidingView>
Chiming in for others who may be facing a similar issue: the ViewCompat.setOnApplyWindowInsetsListener workaround suggested here and here mostly worked for us. However, we also use Braze in-app messages, which overrides the same listener on the root View and thus nullifies the fix.
So, if you find that this fix does not work for you, it could be because something else is overriding the setOnApplyWindowInsetsListener on the root view. We ended up trying a fairly blunt hack to re-override the listener in Activity.onUserInteraction() as well. However, it seems like anything calling setOnApplyWindowInsetsListener risks conflicting with other callers and breaking something else, and I'm not sure how to mitigate that risk.
I'm happy to look for a possible fix and contribute one, if someone can provide a reproducer for the latest main or v0.81.0-rc.1
I tried both upgrading my existing project and a new one using the below command, but in both cases, I ended up with the same error (see below). I'll try again later
npx @react-native-community/cli init rn-81-rc1 --version 0.81.0-rc.1
Git/rn81rc1/node_modules/.generated/launchPackager.command ; exit;
error (0 , _util.styleText) is not a function.
TypeError: (0 , _util.styleText) is not a function
at Object.runServer [as func] (/Git/rn81rc1/node_modules/@react-native/community-cli-plugin/dist/commands/start/runServer.js:74:25)
at async Command.handleAction (/Git/rn81rc1/node_modules/@react-native-community/cli/build/index.js:139:9)
Process terminated. Press <enter> to close the window
in styles.xml file path android/app/src/main/res/values/styles.xml just add this line, will fix
<item name="android:windowOptOutEdgeToEdgeEnforcement">true</item>
Note: No need to use react-native-safe-area-context
in styles.xml file path android/app/src/main/res/values/styles.xml just add this line, will fix
<item name="android:windowOptOutEdgeToEdgeEnforcement">true</item>Note: No need to use
react-native-safe-area-context
FYI https://developer.android.com/about/versions/16/behavior-changes-16. You will have to fix that when targeting 36
@roni-castro-shipt
Updated project configurations to support Android API Level 36 and improvements for keyboard handling I also tested with api 35
ext {
buildToolsVersion = "36.0.0"
minSdkVersion = 24
compileSdkVersion = 36
targetSdkVersion = 36
ndkVersion = "27.1.12297006"
kotlinVersion = "2.0.21"
}
In my case
For Android 15 (API Level 35), avoided using
<item name="android:windowOptOutEdgeToEdgeEnforcement">true</item>
due to layout issues caused by images in the status bar. Instead, I implemented the following Kotlin code to handle keyboard padding in MainActivity.kt
if (Build.VERSION.SDK_INT >= 35) {
val rootView = findViewById<View>(android.R.id.content)
ViewCompat.setOnApplyWindowInsetsListener(rootView) { _, insets ->
val innerPadding = insets.getInsets(WindowInsetsCompat.Type.ime())
rootView.setPadding(
innerPadding.left,
innerPadding.top,
innerPadding.right,
innerPadding.bottom
)
insets
}
}
This code resolves the keyboard issue and ensures proper padding for keyboard input in API Level 35 and 36.
After extensive testing, I found that API Level 36 works fine without the need for the
<item name="android:windowOptOutEdgeToEdgeEnforcement">true</item>
property in the styles.xml file. The app layout and design render correctly with safe area insets and no padding issues.
iOS Platform Considerations:
KeyboardAvoidingView may not work consistently in some cases on iOS, so it's recommended to use KeyboardAwareScrollView for better handling of keyboard input across both platforms.
SafeAreaView from react-native-safe-area-context is utilized to handle the safe areas for all screens, and I’ve used multiple solutions to ensure the app UI works across Android and iOS without issues.
Additional Notes:
If you encounter issues after changing the Gradle version, such as build errors, it is recommended to delete the .gradle folder from your project’s root directory and re-sync the Gradle dependencies.
https://github.com/user-attachments/assets/2a4bedb4-d769-40fb-8538-2a26e84df488
@volo-droid please share we have a fix planned in any of the react native release.
I tried both upgrading my existing project and a new one using the below command, but in both cases, I ended up with the same error (see below). I'll try again later
npx @react-native-community/cli init rn-81-rc1 --version 0.81.0-rc.1
Git/rn81rc1/node_modules/.generated/launchPackager.command ; exit; error (0 , _util.styleText) is not a function. TypeError: (0 , _util.styleText) is not a function at Object.runServer [as func] (/Git/rn81rc1/node_modules/@react-native/community-cli-plugin/dist/commands/start/runServer.js:74:25) at async Command.handleAction (/Git/rn81rc1/node_modules/@react-native-community/cli/build/index.js:139:9) Process terminated. Press <enter> to close the window
@dprevost-LMI did you find a resolution this? I'm having the same issue
@moulie415 nope, I did not retry yet either! Good luck
@dprevost-LMI ok updating from node 20.9.0 to latest stable worked for me. I only realised it was a node issue when I was going through the bug submission process, the "reproducer app" flagged that my node version was incompatible but that didn't happen in my project or in a fresh RN project so sounds like it could still be an issue