react-native-keyboard-controller icon indicating copy to clipboard operation
react-native-keyboard-controller copied to clipboard

KeyboardAvoidingView does not work inside Modals if "prefer Cross-Fade Transitions" are enabled

Open buschco opened this issue 2 months ago • 2 comments

Describe the bug The KeyboardAvoidingView is not expanding

Code snippet

import React, { useState } from "react";
import {
  Modal,
  StyleSheet,
  Text,
  TextInput,
  TouchableOpacity,
  View,
} from "react-native";
import { ScrollView } from "react-native-gesture-handler";
import { KeyboardAvoidingView } from "react-native-keyboard-controller";
import { useSafeAreaInsets } from "react-native-safe-area-context";

import type { ViewProps } from "react-native-svg/lib/typescript/fabric/utils";

const styles = StyleSheet.create({
  flex1: { flex: 1 },
  flexGrow1: { flexGrow: 1 },
  heading: {
    color: "black",
    fontSize: 36,
    marginBottom: 48,
    fontWeight: "600",
  },
  inner: {
    padding: 24,
    flex: 1,
    justifyContent: "space-between",
  },
  textInput: {
    height: 45,
    borderColor: "#000000",
    borderWidth: 1,
    borderRadius: 10,
    marginBottom: 36,
    paddingLeft: 10,
  },
  button: {
    marginTop: 12,
    height: 45,
    borderRadius: 10,
    backgroundColor: "rgb(40, 64, 147)",
    justifyContent: "center",
    alignItems: "center",
  },
  text: {
    fontWeight: "500",
    fontSize: 16,
    color: "white",
  },

  backgroundColorRed: {
    backgroundColor: "red",
  },
});

function C() {
  return (
    <KeyboardAvoidingView
      behavior="padding"
      contentContainerStyle={styles.flex1 as ViewProps["style"]}
      keyboardVerticalOffset={100}
      style={styles.flex1}
      testID="keyboard_avoiding_view.container"
    >
      <ScrollView
        alwaysBounceVertical={false}
        automaticallyAdjustsScrollIndicatorInsets={false}
        contentContainerStyle={styles.flexGrow1}
        contentInset={{ bottom: 30 }}
        keyboardShouldPersistTaps="handled"
        scrollEventThrottle={300}
        scrollIndicatorInsets={{
          right: 1,
          bottom: 30,
        }}
        style={styles.flex1}
      >
        <View style={styles.inner}>
          <Text style={styles.heading}>Header</Text>
          <View>
            <TextInput
              placeholder="Username"
              placeholderTextColor="#7C7C7C"
              style={styles.textInput}
              testID="keyboard_avoiding_view.username"
            />
            <TextInput
              secureTextEntry
              placeholder="Password"
              placeholderTextColor="#7C7C7C"
              style={styles.textInput}
              testID="keyboard_avoiding_view.password"
            />
          </View>
          <TouchableOpacity
            style={styles.button}
            testID="keyboard_avoiding_view.submit"
          >
            <Text style={styles.text}>Submit</Text>
          </TouchableOpacity>
        </View>
      </ScrollView>
    </KeyboardAvoidingView>
  );
}

export default function KeyboardAvoidingViewExample() {
  const [visible, setVisible] = useState(false);

  const insets = useSafeAreaInsets();

  return (
    <View style={{ flex: 1 }}>
      <TouchableOpacity style={styles.button} onPress={() => setVisible(true)}>
        <Text style={styles.text}>Open</Text>
      </TouchableOpacity>
      <C />
      <Modal visible={visible}>
        <View
          style={[
            styles.flex1,
            { paddingTop: insets.top },
            styles.backgroundColorRed,
          ]}
        >
          <TouchableOpacity
            style={styles.button}
            onPress={() => setVisible(false)}
          >
            <Text style={styles.text}>Close</Text>
          </TouchableOpacity>
          <C />
        </View>
      </Modal>
    </View>
  );
}

Repo for reproducing https://github.com/buschco/react-native-keyboard-controller

To Reproduce Steps to reproduce the behavior:

  1. Check out https://github.com/buschco/react-native-keyboard-controller or copy paste code from above
  2. Goto "Settings" -> "Accessibility" -> "Motion"
  3. Enable "Reduce Motion"
  4. Enable "Prefer Cross-Fade Transitions"
  5. Click on one TextInput and see working KeyboardAvoidingView
  6. Click on "Open" and the Screen should turn red now
  7. Click on one TextInput and see not working KeyboardAvoidingView

Screenshots

https://github.com/user-attachments/assets/9db92d81-dcb0-4275-96cf-33ba7bfbf12b

Image
  • Desktop: macOS Version 26.0.1 (25A362)
  • Device: iPhone 16 Pro
  • OS: iOS 26.0
  • RN version: 0.78
  • RN architecture: new fabric
  • JS engine: Hermes
  • Library version: 1.18.6

buschco avatar Oct 05 '25 09:10 buschco

For more context: without "prefer Cross-Fade" transitions it also doesn't work (it's not animating, sometimes in the end KeyboardAvoidingView has incorrect frame)

https://github.com/user-attachments/assets/b4455ced-a09f-42d7-8c1e-ff9766dcae9d

kirillzyusko avatar Oct 13 '25 09:10 kirillzyusko

Still reproducible on iOS 26.1, but it's reproducible even without modal 😲

kirillzyusko avatar Nov 19 '25 10:11 kirillzyusko