React Native TextInput onFocus does not allow onPress of other child components

1.4k Views Asked by At

Nested TextInput component does not allow other components' onPress function to be called. Only when the TextInput is not focused, the onPress works fine.

React Native Version : 0.66.3

Here is my code

export const Component = (props): JSX.Element {
  const { searchText, onChangeSearchText, onClearSearchText } = props
  const [searchViewFocused, setSearchViewFocused] = useState<boolean>(false)
  const searchIcon = searchViewFocused ? "searchActive" : "searchInactive"
  const cancelIcon = searchViewFocused ? "cancelActive" : "cancelInactive"
  return (
    <View style={styles.searchBoxContainer}>
      <View style={[styles.searchBox, searchViewFocused && styles.searchBarActive]}>
        <Icon styles={styles.searchIcon} icon={searchIcon} />
        <TextInput
          style={styles.searchInput}
          onChangeText={onChangeSearchText}
          value={searchText}
          onFocus={() => setSearchViewFocused(true)}
          onBlur={() => setSearchViewFocused(false)}
          autoCompleteType={"off"}
          numberOfLines={1}
        />
        {searchText !== "" && (
          <Pressable style={styles.clearIcon} onPress={onClearSearchText}>
            <Icon icon={cancelIcon} />
          </Pressable>
        )}
      </View>
    </View>
  )
})

Attached are the images of

Expected.

expected

VS

The issue

issue

When the cross icon is pressed on focused state, the textInput is unfocused rather What I am trying to achieve is that the search text gets cleared & the input remains focused.

Note: The onPress works perfectly fine when input is not focused

Any help is appreciated. Thanks!

PS: Tried TouchableOpacity & also I have tried wrapping the components inside a ScrollView to use keyboardShouldPersistTaps='handled' as mentioned in one of the SO answer but to no success.

2

There are 2 best solutions below

0
On BEST ANSWER

Found a workaround to this is to wrap the whole component into a ScrollView and adding the prop keyboardShouldPersistTaps='handled'

Previously I was making the View inside the Component as ScrollView and adding keyboardShouldPersistTaps='handled' which did not work

export const Component = (props): JSX.Element {
  ...
  return (
    <ScrollView contentContainerStyle={styles.searchBoxContainer} 
                keyboardShouldPersistTaps='handled'>
     ...
    </ScrollView>
  )
})

The key was to wrap the entire component inside the ScrollView,

Here's what worked:

<ScrollView keyboardShouldPersistTaps='handled'>
     <Component {...props}/>
</ScrollView>

Guess this was a silly mistake, but worth pointing out!

3
On

You're setting the focus of the entire component based on whether the TextInput has focus. Since the clear button is outside the text input, pressing it causes the component to lose focus.

One solution is to store the TextInput instance in a ref. When the clear button is pressed, you can refocus the text input. I've copied your component below and added some new lines, which are marked in comments.

export const Component = (props): JSX.Element {
  const { searchText, onChangeSearchText, onClearSearchText } = props
  const textInputRef = useRef(null); // new
  const [searchViewFocused, setSearchViewFocused] = useState<boolean>(false)
  const searchIcon = searchViewFocused ? "searchActive" : "searchInactive"
  const cancelIcon = searchViewFocused ? "cancelActive" : "cancelInactive"
  const onClear = () => {
    onClearSearchText();
    textInputRef.current?.focus();
  } // new
  return (
    <View style={styles.searchBoxContainer}>
      <View style={[styles.searchBox, searchViewFocused && styles.searchBarActive]}>
        <Icon styles={styles.searchIcon} icon={searchIcon} />
        <TextInput
          ref={textInputRef} // new
          style={styles.searchInput}
          onChangeText={onChangeSearchText}
          value={searchText}
          onFocus={() => setSearchViewFocused(true)}
          onBlur={() => setSearchViewFocused(false)}
          autoCompleteType={"off"}
          numberOfLines={1}
        />
        {searchText !== "" && (
          <Pressable style={styles.clearIcon} onPress={onClear}> // calls new function
            <Icon icon={cancelIcon} />
          </Pressable>
        )}
      </View>
    </View>
  )
})