Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Modals on iOS do not respond to the presence of the on-screen keyboard #4218

Open
JPStrydom opened this issue Dec 8, 2023 · 10 comments
Open

Comments

@JPStrydom
Copy link

Current behaviour

On web and Android, the Modal component respects the state of the keyboard, adjusting it's height accordingly. On iOS, however, the Modal does not move up when the keyboard is opened.

This issue is likely related to 2172

Expected behaviour

The Modal component should respect the positions of the keyboard and respond accordingly on all platforms.

How to reproduce?

  1. Add a Modal component inside a Portal component.
  2. Add content to the Modal component and open the Modal.
  3. Open the device on-screen keyboard on an iOS device.
  4. Notice how the Modal doesn't respond (move up) to accommodate the keyboard, even though there is empty space available above the modal.

Preview

iOS:
image

Android:
image

What have you tried so far?

We're currently following the workaround listed here.

Your Environment

software version
ios x
android x
react-native 0.71.14
react-native-paper 5.11.2
node 20.9.0
npm or yarn 10.1.0
expo sdk 48.0.20
@Bi0max
Copy link
Contributor

Bi0max commented Jan 22, 2024

Having the same issue

@lukewalczak
Copy link
Member

@Bi0max please add your issue reproduction

@Bi0max
Copy link
Contributor

Bi0max commented Jan 24, 2024

@lukewalczak , hi , it's literally the same as the OP described. It is reproduced just with and empty Modal and an opened keyboard on iOS.

@Sanal
Copy link

Sanal commented Jan 27, 2024

Hello! I confirm the issue. It seems there is a problem with Portal and its keyboard avoiding behavior on iOS. It also makes SnackBar (placed in Portal) appear under the keyboard on iOS. Reproduced it the same way the issue's author described.

Screen.Recording.2024-01-27.at.15.51.45.mov

My environment

software version
ios 17.2
android 13.0
react-native 0.72.10
react-native-paper 5.12.2
node 21.3.0
yarn 1.22.21

@foxysolutions
Copy link

Same issue after upgrading to latest and placing modal within Portal component.

@Abdalrzakalsouki
Copy link

Abdalrzakalsouki commented Feb 27, 2024

Same issue, Portal does not response to keybored in IOS even with KeyboardAvoidingView, for anyone who is looking for a solution, you can use Modal from react nativre for IOS with keyboredAvoidView, it works fine

@JPStrydom
Copy link
Author

Has there been any update or progress on this?

@jahirfiquitiva
Copy link

jahirfiquitiva commented Aug 21, 2024

I have fixed this by patching the react-native-paper dependency (using yarn)

Here I share the changes in case it's helpful for others.

There's probably a better approach, but this might suffice while RNP implement an actual fix.

cc @lukewalczak

Please ignore some formatting changes in here

diff --git a/src/components/Modal.tsx b/src/components/Modal.tsx
index 313ecee43bde4a0b6be9cbd13b673452725f0f6e..12a7e3d0494a5e256ba5e22a89d71572df547789 100644
--- a/src/components/Modal.tsx
+++ b/src/components/Modal.tsx
@@ -7,6 +7,8 @@ import {
   Pressable,
   View,
   ViewStyle,
+  KeyboardAvoidingView,
+  Platform,
 } from 'react-native';
 
 import { useSafeAreaInsets } from 'react-native-safe-area-context';
@@ -177,11 +179,7 @@ function Modal({
       return true;
     };
 
-    const subscription = addEventListener(
-      BackHandler,
-      'hardwareBackPress',
-      onHardwareBackPress
-    );
+    const subscription = addEventListener(BackHandler, 'hardwareBackPress', onHardwareBackPress);
     return () => subscription.remove();
   }, [dismissable, dismissableBackButton, hideModal, visible]);
 
@@ -204,17 +202,16 @@ function Modal({
     <Animated.View
       pointerEvents={visible ? 'auto' : 'none'}
       accessibilityViewIsModal
-      accessibilityLiveRegion="polite"
+      accessibilityLiveRegion='polite'
       style={StyleSheet.absoluteFill}
       onAccessibilityEscape={hideModal}
-      testID={testID}
-    >
+      testID={testID}>
       <AnimatedPressable
         accessibilityLabel={overlayAccessibilityLabel}
-        accessibilityRole="button"
+        accessibilityRole='button'
         disabled={!dismissable}
         onPress={dismissable ? hideModal : undefined}
-        importantForAccessibility="no"
+        importantForAccessibility='no'
         style={[
           styles.backdrop,
           {
@@ -225,21 +222,20 @@ function Modal({
         testID={`${testID}-backdrop`}
       />
       <View
-        style={[
-          styles.wrapper,
-          { marginTop: top, marginBottom: bottom },
-          style,
-        ]}
-        pointerEvents="box-none"
-        testID={`${testID}-wrapper`}
-      >
-        <Surface
-          testID={`${testID}-surface`}
-          theme={theme}
-          style={[{ opacity }, styles.content, contentContainerStyle]}
-        >
-          {children}
-        </Surface>
+        style={[styles.wrapper, { marginTop: top, marginBottom: bottom }, style]}
+        pointerEvents='box-none'
+        testID={`${testID}-wrapper`}>
+        <KeyboardAvoidingView
+          behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
+          keyboardVerticalOffset={100}
+          style={styles.keyboardAvoidingView}>
+          <Surface
+            testID={`${testID}-surface`}
+            theme={theme}
+            style={[{ opacity }, styles.content, contentContainerStyle]}>
+            {children}
+          </Surface>
+        </KeyboardAvoidingView>
       </View>
     </Animated.View>
   );
@@ -260,4 +256,10 @@ const styles = StyleSheet.create({
     backgroundColor: 'transparent',
     justifyContent: 'center',
   },
+  keyboardAvoidingView: {
+    display: 'flex',
+    flexDirection: 'column',
+    alignItems: 'stretch',
+    justifyContent: 'center',
+  },
 });

Here's proof of it working:

iOS
iPhone.15.Pro.Screen.Recording.Aug.21.mp4
Android
Shot.2024-08-21.at.18.10.45.mp4

@jahirfiquitiva
Copy link

Oh, while my "fix" works in some cases, it can cause this behavior when there's long content in the modal/dialog. Just FYI

@nasirdeveloper
Copy link

Still the issue has been there (Not resolved)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

8 participants