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

iOS Keyboard Autofill/SecureTextEntry makes content jump/glitch when focusing on next TextInput #31722

Closed
samuelbeaulieu opened this issue Jun 15, 2021 · 13 comments
Labels
API: Keyboard Component: TextInput Related to the TextInput component. Platform: iOS iOS applications. Stale There has been a lack of activity on this issue and it may be closed soon.

Comments

@samuelbeaulieu
Copy link

samuelbeaulieu commented Jun 15, 2021

Description

I have a page in my app with two TextInput inside views covering the whole screen.

The two TextInput have a ref ref={refTextInput1}, ref={refTextInput2}.
They also have a onSubmitEditing onSubmitEditing={() => refTextInput2().current.focus()}, onSubmitEditing={() => refTextInput1().current.focus()}.

So, when I press "return" on the keyboard, the focus will switch to the desired input but it's also making the whole screen jump/glitch which is really annoying and not wanted.

The focus should switch to the desired input without making the whole screen jump/glitch.

I searched everywhere on StackOverflow and Github Issues but didn't find a lot of issues with this particular problem.
At first, I thought I had a problem similar to #30207, but after a while trying to find the problem, I think I found it.

The problem only occurs(I think) when Autofill Passwords is enabled in Settings>Passwords>Autofill Passwords.
If I disable Autofill Passwords, the jump/glitch does not occurs.

I also noticed that the keyboard event is always triggered twice on focus with Autofill Passwords enabled, and only once on focus with Autofill Passwords disabled. It may also be related. (See the console when running the snack example.)

I looked at other apps, and they all seems fine in the same type of login screen. Instagram for example doesn't have this problem.

It might also be the way I made my screen, if there's a better way to do the same or similar screen, I would be open to suggestions.

React Native version:

System:
    OS: macOS 11.4
    CPU: (8) x64 Intel(R) Core(TM) i7-4770HQ CPU @ 2.20GHz
    Memory: 137.61 MB / 16.00 GB
    Shell: 5.8 - /bin/zsh
  Binaries:
    Node: 14.17.0 - /usr/local/bin/node
    Yarn: Not Found
    npm: 6.14.13 - /usr/local/bin/npm
    Watchman: 4.9.0 - /usr/local/bin/watchman
  Managers:
    CocoaPods: 1.10.1 - /usr/local/bin/pod
  SDKs:
    iOS SDK:
      Platforms: iOS 14.5, DriverKit 20.4, macOS 11.3, tvOS 14.5, watchOS 7.4
    Android SDK:
      API Levels: 22, 23, 24, 25, 26, 27, 28, 29, 30
      Build Tools: 28.0.3, 29.0.2, 30.0.2
      System Images: android-30 | Google APIs Intel x86 Atom
      Android NDK: Not Found
  IDEs:
    Android Studio: 4.1 AI-201.8743.12.41.6953283
    Xcode: 12.5/12E262 - /usr/bin/xcodebuild
  Languages:
    Java: 1.8.0_271 - /usr/bin/javac
  npmPackages:
    @react-native-community/cli: Not Found
    react: 17.0.1 => 17.0.1 
    react-native: 0.64.1 => 0.64.1 
    react-native-macos: Not Found
  npmGlobalPackages:
    *react-native*: Not Found

Steps To Reproduce

  1. Make sure Autofill Passwords is enabled in Settings>Passwords>Autofill Passwords.
  2. Have at least two TextInput with a view taking the whole screen space.
  3. Focus on the next TextInput using "return" on the keyboard.

I also noticed that the keyboard event is always triggered twice on focus with Autofill Passwords enabled, and only once on focus with Autofill Passwords disabled. It may also be related. (See the console when running the snack example.)

Expected Results

When pressing "return" on the keyboard, the focus should switch to the desired input without making the whole screen jump/glitch. Like when Autofill Passwords is disabled in Settings>Passwords>Autofill Passwords.

Snack, code example, screenshot, or link to a repository:

Snack 1 is a simpler version of my issue.
Snack 1: simple-keyboard-autofill-issue

Snack 2 is closer to what I really have in my app.
Snack 2: my-app-keyboard-autofill-issue

Minimal code example: (from simple-keyboard-autofill-issue)

import React, { useState, useRef, useEffect } from 'react';
import { Text, View, KeyboardAvoidingView, TouchableWithoutFeedback, Keyboard, Platform, TextInput } from 'react-native';

export default function App() {
  const [username, setUsername] = useState('');
  const [password, setPassword] = useState('');

  const refUsernameInput = useRef(null);
  const refPasswordInput = useRef(null);

  useEffect(() => {
    Keyboard.addListener('keyboardWillShow', keyboardWillShow);
    Keyboard.addListener('keyboardWillHide', keyboardWillHide);
s
    // cleanup function
    return () => {
      Keyboard.removeListener('keyboardWillShow', keyboardWillShow);
      Keyboard.removeListener('keyboardWillHide', keyboardWillHide);
    };
  }, []);

  const keyboardWillShow = () => {
    console.log('keyboardWillShow');
  };

  const keyboardWillHide = () => {
    console.log('keyboardWillHide');
  };

  return (
    <KeyboardAvoidingView behavior={Platform.OS === 'ios' ? 'padding' : 'height'} style={{ flex: 1 }}>
      <TouchableWithoutFeedback onPress={Keyboard.dismiss}>
        <View style={{ flex: 1, justifyContent: 'space-around', paddingHorizontal: 20 }}>
            <TextInput
              blurOnSubmit={false}
              keyboardType="email-address"
              placeholder="Username or email"
              textContentType="username" // iOS
              onSubmitEditing={() => refPasswordInput.current.focus()}
              onChangeText={setUsername}
              value={username}
              ref={refUsernameInput}
              style={{
                borderColor: '#000',
                borderWidth: 0.5,
                height: 45,
                paddingHorizontal: 20,
                marginBottom: 5,
              }}
            />
            <TextInput
              blurOnSubmit={false}
              keyboardType="default"
              placeholder="Password"
              secureTextEntry
              textContentType="password" // iOS
              onSubmitEditing={() => refUsernameInput.current.focus()}
              onChangeText={setPassword}
              value={password}
              ref={refPasswordInput}
              style={{
                borderColor: '#000',
                borderWidth: 0.5,
                height: 45,
                paddingHorizontal: 20,
              }}
            />
        </View>
      </TouchableWithoutFeedback>
    </KeyboardAvoidingView>
  );
}

Here you can see the screen recording taken from an iPhone 11 Pro with iOS 14.6: (Note that secureTextEntry was temporarily disabled while screen recording, the problem is still present)

RPReplay_Final1623718912.MP4
@samuelbeaulieu samuelbeaulieu changed the title iOS Keyboard autofill makes content jump/glitch when focusing on next TextInput iOS Keyboard Autofill/SecureTextEntry makes content jump/glitch when focusing on next TextInput Jun 15, 2021
@samuelbeaulieu
Copy link
Author

UPDATE: I made another example: simple-keyboard-autofill-issue-2

In this example, I have 4 TextInput with only blurOnSubmit, onSubmitEditing and ref. Only the last TextInput has secureTextEntry.

The first two TextInput are focusing each other on "return" press, no problem with those two, like it should be.

The last two TextInput are also focusing each other on "return" press, the bug/jump/glitch happens with both TextInput.
If I remove the secureTextEntry prop from the last input(line 60), the bug/jump/glitch no longer occurs.

I really think the bug is caused by the Autofill Passwords feature on iOS.

Here's a screen recording of the new snack example, taken from an iPhone 11 Pro with iOS 14.6:

RPReplay_Final1623798783.MP4

@samuelbeaulieu
Copy link
Author

UPDATE 2: I made yet another example: keyboardavoidingview

This time I used the example provided right in the KeyboardAvoidingView documentation on reactnative.dev, added the same props from my other examples; focus on onSubmitEditing, blurOnSubmit and ref.

Once again, If I remove the secureTextEntry prop from the last input(line 27), the bug/jump/glitch no longer occurs.

Here's a screen recording of the this snack example, taken from an iPhone 11 Pro with iOS 14.6:

RPReplay_Final1623807401.MP4

@vvdodiya
Copy link

@samuelbeaulieu did you find any solution? I am facing the same issue.

@samuelbeaulieu
Copy link
Author

@vvdodiya I did not. I'll keep you/this issue updated if I do. If you find something, please keep me updated too.

@Cmonorail
Copy link

same issue...

@safaiyeh safaiyeh added API: Keyboard Component: TextInput Related to the TextInput component. Platform: iOS iOS applications. and removed Needs: Triage 🔍 labels Aug 2, 2021
@mykytabatrak
Copy link

Maybe it'll help somebody, but I decided to use IQKeyboardManager for iOS, and this for android, to be exact I've set android:windowSoftInputMode="stateVisible". Works like a charm now.

@CDBridger
Copy link

this seems like a regression right? I'm getting the same issue but I used to use this pattern in older versions of react native without this occurring.

@TereshchenkoVlad
Copy link

I have the same problem.

@ashirkhan94
Copy link

ashirkhan94 commented May 16, 2024

Hi
This TextInput prop fix my problem textContentType='oneTimeCode'
pls refer below link
https://github.com/facebook/react-native/issues/39411#issuecomment-1746484565

@jurmadani
Copy link

Hi This TextInput prop fix my problem textContentType='oneTimeCode' pls refer below link https://github.com/facebook/react-native/issues/39411#issuecomment-1746484565

I can confirm this solved the issue.

@Pixelatex
Copy link

Pixelatex commented Jun 8, 2024

I worked around this in a creative way...


export function Password({ onChange, value, placeholder }: Props) {
  const [hideValue, setHideValue] = useState(true)
  const [pwd, setPwd] = useState<string>(value || '')

  const censored = pwd.replace(/./g, '*')
  return (
    <TextInput
      right={
        <TextInput.Icon onPress={() => setHideValue(!hideValue)} icon="eye" />
      }
      value={hideValue ? censored : pwd}
      placeholder={placeholder}
      onChangeText={text => {
        let newPwd = pwd
        if (text.length < pwd.length) {
          newPwd = pwd.substring(0, pwd.length - 1)
        } else {
          const newEntry = text.slice(-1)
          newPwd = pwd + newEntry
        }

        onChange(newPwd)
        setPwd(newPwd)
      }}
  )
}

It keeps the password in a state hook and censors it manually to ***. It might not look super clean but it's one way to solve it

@react-native-bot
Copy link
Collaborator

This issue is stale because it has been open 180 days with no activity. Remove stale label or comment or this will be closed in 7 days.

@react-native-bot react-native-bot added the Stale There has been a lack of activity on this issue and it may be closed soon. label Dec 6, 2024
@react-native-bot
Copy link
Collaborator

This issue was closed because it has been stalled for 7 days with no activity.

@react-native-bot react-native-bot closed this as not planned Won't fix, can't repro, duplicate, stale Dec 13, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
API: Keyboard Component: TextInput Related to the TextInput component. Platform: iOS iOS applications. Stale There has been a lack of activity on this issue and it may be closed soon.
Projects
None yet
Development

No branches or pull requests