Skip to content

KeyboardProvider modifies Android insets in edge-to-edge mode on Android 15+ #1488

@abdelrahman-ali-vodafone

Description

Describe the bug
After enabling KeyboardProvider with navigationBarTranslucent, Android safe-area/window insets change unexpectedly over time on Android 15+ (API 35+) in Landscape mode.

Code snippet

import React, { useEffect } from 'react'
import { StyleSheet, Platform } from 'react-native'
import {
  SafeAreaProvider,
  SafeAreaView,
  useSafeAreaInsets
} from 'react-native-safe-area-context'
import { KeyboardProvider } from 'react-native-keyboard-controller'

const RootInsetsLogger = () => {
  const insets = useSafeAreaInsets()
  useEffect(() => {
    console.log('[App] safe area insets', insets)
  }, [insets])
  return null
}

export default function App() {
  return (
    <SafeAreaProvider>
      <RootInsetsLogger />
      <KeyboardProvider navigationBarTranslucent>
        <SafeAreaView
          edges={Platform.OS === 'ios' ? [] : ['bottom', 'left', 'right']}
          style={styles.container}
        />
      </KeyboardProvider>
    </SafeAreaProvider>
  )
}

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

Observed behavior
Insets reported by useSafeAreaInsets() transition through multiple states during startup/runtime, for example:

[App] safe area insets {
  "left": 0,
  "bottom": 0,
  "right": 48,
  "top": 24
}
[App] safe area insets {
  "left": 0,
  "bottom": 0,
  "right": 48,
  "top": 0
}
[App] safe area insets {
  "left": 0,
  "bottom": 0,
  "right": 0,
  "top": 24
}

Expected behavior
With edge-to-edge enabled, insets should be stable and predictable for layout usage, or there should be clear guidance on expected transient inset states and when values are considered final.

Environment

  • Android 15+ (API 35+)
  • React Native 0.79.3
  • react-native-keyboard-controller 1.21.8
  • react-native-safe-area-context 5.4.0
  • Hermes enabled

Additional context
On Android 14 and lower, everything works correctly and inset values remain stable.
The problem appears on Android 15+ only, where insets change during runtime after enabling KeyboardProvider edge-to-edge behavior.
This inset change is what surfaces the issue in react-native-modal: the modal can overlap and render under the navigation bar.
So this is version-dependent behavior: not reproducible on older Android versions, reproducible on Android 15+.
Also, my layout depends on useSafeAreaInsets() values (especially left/right insets) to calculate horizontal padding, so inset changes directly affect modal/content horizontal spacing and positioning

Screenshots

Image Android 15

Image Android 14

Workaround: wrapping modal content in its own SafeAreaView resolves the overlap on Android 15+ in my app setup.
Without that modal-local SafeAreaView, modal content can render under the navigation bar when KeyboardProvider edge-to-edge is enabled.
In my case, the workaround became reliable after I removed manual inset-based layout handling from useSafeAreaInsets and instead wrapped the component with SafeAreaView and relied on SafeAreaView edges to handle insets.
This suggests inset handling differs between root content and modal surface on Android 15+, even when logged inset values look similar.
On Android 14 and below, this behavior is not reproducible in the same setup.

    <Modal
            isVisible={showModal}
            style={styles.modalStyle}
            animationIn="slideInUp"
            backdropTransitionInTiming={650}
            backdropTransitionOutTiming={0}
            backdropOpacity={1}
            backdropColor="yellow"
            statusBarTranslucent
          >
            <SafeAreaView
              edges={Platform.OS === 'ios' ? [] : ['bottom', 'left', 'right']}
              style={{ flex: 1, justifyContent: 'flex-end' }}
            >
              {Content}
            </SafeAreaView>
          </Modal>
Image Android 15 after wraping the Modal content with SafeAreaView

Metadata

Metadata

Assignees

Labels

No labels
No labels

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions