Keep focus on textInput when interacting with other elements in React Native

561 Views Asked by At

I'm trying to create a text input using React Native and React Native Elements with an autocomplete list.

The desired behaviour is - on focusing the text input, the autocomplete list opens. The user can then interact with either the text input or the autocomplete list, and the focus will stay on the text input. When the user taps outside of either the text input or the autocomplete list, the text input blurs and the autocomplete list closes.

See example here:

import * as React from 'react';
import { Keyboard, Text, View, SafeAreaView, ScrollView, TouchableHighlight } from 'react-native';
import { ListItem, Input } from '@rneui/themed';

export default function App() {
  const [autoIsOpen, openAuto] = React.useState(false);

  function Autocomplete() {
    const list = ['abc', 'def', 'ghi', 'jkl', 'mno', 'pqr'];
    return list.map((item) => {
      return (
        <TouchableHighlight
          onPress={()=>{console.log('do some action');}}
        >
          <ListItem bottomDivider>
            <ListItem.Content>
              <ListItem.Title>
                <Text>{item}</Text>
              </ListItem.Title>
            </ListItem.Content>
          </ListItem>
        </TouchableHighlight>
      );
    });
  }

  return (
    <SafeAreaView style={{ flex: 1, }}>
      <ScrollView 
        keyboardShouldPersistTaps="handled"
        onPress={Keyboard.dismiss}
        style={{
          flex: 1,
        }}
      >
        <View style={{ flex: 1, }}>
          <View style={{ padding: 10, alignItems: 'center', }}>
            <Input
              onFocus={() => {openAuto(true);}}
              onBlur={() => {openAuto(false);}}
            />
          </View>
          <View style={{ padding: 10, alignItems: 'center', }}>
            <ScrollView
              keyboardShouldPersistTaps="handled"
              style={{ width: '100%', height: 150, }}
            >
              { autoIsOpen ? <Autocomplete /> : null }
            </ScrollView>
          </View>
        </View>
      </ScrollView>
    </SafeAreaView>
  );
}

Or Snack: https://snack.expo.dev/@jdgordon01/autocomplete-test

This relies on a combination of keyboardShouldPersistTaps="handled" and Keyboard.dismiss() to manually keep the focus on the text input unless something other than the input/autocomplete is interacted with. This gets close to the desired outcome with the following issues:

  • On iOS, it is easy to trigger the Keyboard.dismiss() unintentionally. The autocomplete includes a ScrollList, and I find that if you scroll too quickly, the Keyboard.dismiss() triggers most of the time.

  • This method does not work at all on web. Clicking the autocomplete list will automatically unfocused the text input (and hence close the autocomplete before onPress is triggered)

How can I get the desired behaviour to work consistently across platforms?

0

There are 0 best solutions below