react-native-paper icon indicating copy to clipboard operation
react-native-paper copied to clipboard

TextInput autofocus is not opening keyboard on Android

Open JestemTrzcinska opened this issue 1 year ago • 6 comments

Current behaviour

Trying to improve user experience by auto focusing to input and showing keyboard. On iOS everything works fine, but on Android two thinks are happening.

TextInput gets auto focused on Android but:

  1. keyboard is not showing automatically, only after direct pressing text input
  2. I have bottom sheet that is behind modal with text input and after pressing on TextInput to get the keyboard open the BottomSheet rises for no reason.

Expected behaviour

When opening modal (TextInput initial) the TextInput is focused and keyboard is open (as on iOS)

How to reproduce?

First case code example: code example on snack.expo.dev

Preview

Second case preview:

2 case (2) 2 case (1)

What have you tried so far?

update react-native-paper

Your Environment

software version
ios 17.0
android 34
react-native ^0.73.6
react-native-paper ^5.12.3
node 18.18.0
npm or yarn 9.8.1
expo sdk x.x.x

JestemTrzcinska avatar Jul 18 '24 12:07 JestemTrzcinska

@JestemTrzcinska let me take a look into this issue! 👀

kamilkedzierski avatar Jul 25 '24 08:07 kamilkedzierski

So, I've been looking into this issue with TextInput using autofocus inside a Modal from react-native on Android. Turns out, it's a known problem. The Modal component creates a new root view, and sometimes the keyboard doesn't show up because the modal's new view hierarchy isn't fully rendered by the time the TextInput tries to focus.

I've found a workaround that's helped others with the same issue. You can check it out here: autofocus workaround.

On another note, I've tested the TextInput autofocus with BottomSheetModal from @gorhom/bottom-sheet, and it worked perfectly without any need for workarounds. If it's possible to use @gorhom/bottom-sheet in your project, it might be worth a try! Unfortunately, I couldn't add @gorhom/bottom-sheet to an Expo Snack, but here's a snippet you can use.

Video of BottomSheetModal from @gorhom/bottom-sheet https://github.com/user-attachments/assets/ca663390-baff-4ec8-9466-5dad587b29e5

import * as React from 'react';
import { useState } from 'react';
import { Button, StyleSheet, View } from 'react-native';

import {
  BottomSheetModal,
  BottomSheetModalProvider,
  BottomSheetView,
} from '@gorhom/bottom-sheet';
import { TextInput } from 'react-native-paper';

export const Example = () => {
  const [searchFilter, setSearchFilter] = useState('');

  const bottomSheetModalRef = React.useRef<BottomSheetModal>(null);

  const handlePresentModalPress = React.useCallback(() => {
    bottomSheetModalRef.current?.present();
  }, []);
  const handleSheetChanges = React.useCallback((index: number) => {
    console.log('handleSheetChanges', index);
  }, []);


  return (
    <View style={styles.container}>
      <Button title={'show modal'} onPress={handlePresentModalPress} />
      <BottomSheetModalProvider>
        <BottomSheetModal
          ref={bottomSheetModalRef}
          onChange={handleSheetChanges}
          snapPoints={['25%', '50%', '75%']} 
        >
          <BottomSheetView style={styles.contentContainer}>
            <TextInput
              textColor={'black'}
              value={searchFilter}
              onChangeText={setSearchFilter}
              style={styles.textInput}
              dense
              mode="outlined"
              outlineStyle={styles.outlineStyle}
              autoFocus
            />
          </BottomSheetView>
        </BottomSheetModal>
      </BottomSheetModalProvider>
    </View>
  );
};

const styles = StyleSheet.create({
  textInput: {
    fontSize: 17,
    width: '100%',
    marginTop: 10,
  },
  container: {
    flex: 1,
    padding: 24,
    justifyContent: 'center',
    backgroundColor: '#f6f6f6',
  },
  contentContainer: {
    flex: 1,
    alignItems: 'center',
    width: '100%',
    padding: 10,
  },
  outlineStyle: {
    borderRadius: 10,
    borderWidth: 1,
    justifyContent: 'center',
  },
});

kamilkedzierski avatar Jul 25 '24 14:07 kamilkedzierski

@JestemTrzcinska Hey! Just checking in—can we close this issue, or do you have any questions? 😊

kamilkedzierski avatar Aug 02 '24 17:08 kamilkedzierski

@kamilkedzierski thanks for the workaround! any chance for the autofocus to work with modal in the future? you can close the issue ;)

JestemTrzcinska avatar Aug 05 '24 08:08 JestemTrzcinska

try this: setTimeout(() => textInputRef.current?.focus(), 100);

It worked for me.

anggaprytn avatar Sep 06 '24 04:09 anggaprytn

Weirdly, this worked for me:

const textInputRef = useRef<TextInput>(null);
const { current: textInput } = textInputRef;
const getTextInputFunction = useCallback((): KeyOfTextInput => visible ? 'focus' : 'blur', [visible]);
const handleTextInputFocus = useCallback(
  () => {
    if (textInput) {
      textInput[getTextInputFunction()]();
    }
  },
  [getTextInputFunction, textInput]
);
useEffect(handleTextInputFocus, [handleTextInputFocus]);

but this didn't:

const textInputRef = useRef<TextInput>(null);
useEffect(() => {
  if (textInputRef.current) {
    if (visible) {
      textInputRef.current.focus();
    } else {
      textInputRef.current.blur();
    }
  }
}, [textInputRef, visible]);

Maybe I'm just doing something weird. ¯_(ツ)_/¯

Gergling avatar May 13 '25 21:05 Gergling