CORE JSC

International Technology Partnership

Mobile Development

Fixing React Native KeyboardAvoidingView That Doesn't Work Inside a Modal on iOS

A text input that correctly shifts out from under the keyboard on the main screen gets completely covered the moment the exact same input is placed inside a Modal. The screen's own KeyboardAvoidingView wasn't forgotten — it simply has no effect on content that iOS is rendering in an entirely separate window from the screen it's wrapping.

Core JSC Team·November 3, 2026
React NativeiOSMobile DevelopmentKeyboardModals

The Problem

A screen's text input correctly shifts upward as the keyboard appears, thanks to a KeyboardAvoidingView wrapping the screen's content — standard, working behavior. The same input, moved into a Modal component presented from that same screen (a bottom sheet, a form dialog), behaves completely differently: the keyboard slides up and covers it entirely, with no adjustment at all, as if no keyboard-avoidance logic exists for that content, even though the exact same wrapping component is used.

Why It Happens

On iOS, React Native's Modal renders its content in a genuinely separate native window, not just a visually-overlaid view

Unlike a view that's simply positioned on top of other content within the same screen, iOS's Modal presentation creates an entirely distinct native window in the platform's own view hierarchy. A KeyboardAvoidingView wrapping the screen behind the modal operates within that screen's own window — it has no reach into, or effect on, content rendered inside the modal's separate window, regardless of how the component tree looks in the JavaScript/React layer.

The modal's content needs its own, independent KeyboardAvoidingView, because none is inherited from the parent screen

Because the modal is architecturally its own window rather than a child of the screen behind it, the keyboard-avoidance behavior has to be set up again, from scratch, specifically for whatever's rendered inside that modal. A developer who already added KeyboardAvoidingView to the main screen can reasonably — but incorrectly — assume that coverage extends to anything presented on top of it, when the modal's own content tree is actually a separate rendering context with no inherited keyboard-handling at all.

The correct behavior prop and vertical offset for a modal's content frequently differ from what worked on the main screen

Even once a KeyboardAvoidingView is added inside the modal, the behavior prop ("padding" versus "height," on iOS specifically) and the keyboardVerticalOffset value that worked correctly for the main screen's layout don't automatically carry over to the modal's different layout and positioning, since the correct values depend on the specific view hierarchy and spacing above the input in each case.

The Fix

1. Wrap the modal's own content in its own KeyboardAvoidingView, independent of anything on the screen behind it

<Modal visible={isVisible} animationType="slide">
  <KeyboardAvoidingView
    behavior={Platform.OS === "ios" ? "padding" : "height"}
    style={{ flex: 1 }}
  >
    <TextInput />
  </KeyboardAvoidingView>
</Modal>

Adding a dedicated KeyboardAvoidingView specifically inside the modal, rather than relying on the one wrapping the screen behind it, is the direct fix — it gives the modal's own separate native window the keyboard-avoidance logic that genuinely has to exist independently for content rendered there.

2. Use "padding" rather than "height" as the behavior on iOS specifically, since it tends to produce smoother results for modal content

<KeyboardAvoidingView
  behavior={Platform.OS === "ios" ? "padding" : "height"}
>

The "padding" behavior adjusts the view's bottom padding rather than its measured height, which commonly avoids a visible resize flicker that the "height" behavior can produce specifically within a modal's more constrained layout — this is a starting-point recommendation to test against the specific modal's content, not a universal rule for every layout.

3. Set keyboardVerticalOffset explicitly for the modal, rather than reusing the value tuned for the main screen

<KeyboardAvoidingView
  behavior="padding"
  keyboardVerticalOffset={Platform.OS === "ios" ? 20 : 0} // tune for this modal's own layout
>

Because the offset compensates for whatever's positioned above the input — which differs between the main screen's layout and the modal's own header, padding, or safe-area insets — tuning this value specifically against the modal's actual content, rather than copying the number that worked on the main screen, is what produces correct spacing instead of an input still partially covered or an overcorrected gap.

4. On Android, verify the modal's own windowSoftInputMode behavior rather than assuming it matches iOS's requirements

<Modal
  visible={isVisible}
  // On Android, confirm the modal's statusBarTranslucent and related
  // props don't interfere with the system's own keyboard-resize handling,
  // which often needs less manual KeyboardAvoidingView tuning than iOS does
  statusBarTranslucent
>

Android's own soft-keyboard resize handling frequently requires a different, often lighter touch than iOS's inside a modal, so testing the modal specifically on Android rather than assuming the iOS-tuned values transfer directly is what catches a fix that looks complete on one platform but still needs adjustment on the other.

Why This Works

Each step addresses the core architectural fact that a modal's content lives in a genuinely separate rendering context from the screen behind it, so nothing about that screen's own keyboard handling extends into it automatically. Adding a dedicated KeyboardAvoidingView inside the modal is the direct fix for the missing coverage. Preferring "padding" as the behavior addresses a common visual rough edge specific to modal content. Tuning the vertical offset for the modal's own layout, rather than reusing the main screen's value, accounts for the different spacing context a modal typically has. And verifying Android separately catches platform-specific differences in how each OS actually handles keyboard resizing.

Conclusion

A text input that's covered by the keyboard specifically inside a modal, while working correctly on the main screen, isn't a sign that KeyboardAvoidingView stopped working — it's the modal being a genuinely separate native rendering context on iOS, with no inherited keyboard-avoidance behavior from whatever wraps the screen behind it. Wrap the modal's own content in its own KeyboardAvoidingView, prefer "padding" as the iOS behavior for smoother results inside a modal, tune keyboardVerticalOffset specifically for the modal's layout rather than reusing the main screen's value, and verify the fix separately on Android rather than assuming the iOS-tuned values carry over.