ifelsething logoifelsething

How to Focus Previous React Native TextInput on Backspace?

Published On: 2024-02-20
Posted By: Harish

How to Automatically Focus Previous React Native TextInput on Backspace

We have seen a way to focus on the next text input after entering a value to the current input. We considered a simple OTP validation as an example. This post is a continuation of that post. Check the first post HERE.

In this post, we will see a way to focus on previous text input on deletion of value from current input. We will track the Backspace key event to focus on previous input.

Add onKeyPress Callback

We can get a backspace event with the help of onKeyPress callback. So, add onKeyPress callback to second, third and fourth text inputs and get the type of the key event.

For checking event type, we will create a new function called handleKeyPress and pass to every text input's onKeyPress callback.


...
const handleKeyPress = (e: NativeSyntheticEvent<TextInputKeyPressEventData>) => {
    const key = e.nativeEvent.key;
    return key === "Backspace" ? true : false;
};
...

<TextInput
  ...
  onKeyPress={(e) => {
    const isBack = handleKeyPress(e);
  }}
  ...
/>

...

Function handleKeyPress returns true if the occurred event is Backspace. If not, returns false.

As we want to focus on previous text input on the backspace event, we check for truthy and use the focus() method to shift focus on to the previous field.


...

//This is the second input which will focus on the first input after deleting the second input's value.
<TextInput
  ...
  onKeyPress={(e) => {
    const isBack = handleKeyPress(e);
    if(isBack) {
      firstRef.current.focus();
    }
  }}
  ...
/>

...

Last text input will shift to the previous input event even without clicking backspace. This weird behavior is because of occurring a backspace event with an actual event when the input is empty in onKeyPress callback.

As we are checking for a backspace event to focus on the previous field, this behavior will cause it to go back to the third field without pressing any backspace.

To clear this issue, I added a condition to focus on the current field if the event is not a backspace event. In our case, that is the fourth <TextInput> field.

...

//This is the last input (fourth input) which will focus on the same input if the event is not a backspace event.
<TextInput
  ...
  onKeyPress={(e) => {
    const isBack = handleKeyPress(e);
    if(isBack) {
      thirdref.current.focus();
    } else {
      fourthRef.current.focus();
      fourthRef.current.blur();
    }
  }}
  ...
/>

...

blur() method of text input is the opposite of focus(). It removes the focus and collapses the opened keyboard.

If you run the app, it will function like the video below.

Complete code,

//app.tsx
import { useRef } from 'react';
import {
  View,
  Text,
  StyleSheet,
  TextInput,
  NativeSyntheticEvent,
  TextInputKeyPressEventData
} from "react-native";

export const App = () => {
  const firstRef = useRef<any>(null);
  const secondRef = useRef<any>(null);
  const thirdRef = useRef<any>(null);
  const fourthRef = useRef<any>(null);
  const onKeyPress = (e: NativeSyntheticEvent<TextInputKeyPressEventData>) => {
    const key = e.nativeEvent.key;
    return key === "Backspace" ? true : false;
  };
  return (
    <View style={styles.container}>
      <Text style={styles.text}>
        ifelsething.com
      </Text>
      <Text style={styles.text}>
        Automatically focus on previous text input on backspace.
      </Text>
      <View style={styles.block}>
        <TextInput
          maxLength={1}
          style={styles.input}
          ref={firstRef}
          textAlign='center'
          autoFocus={true}
          showSoftInputOnFocus={true}
          keyboardType='numeric'
          onChangeText={(t: string) => {
            if(!t) return;
            console.log("First: ", t)
            secondRef.current.focus();
          }}
        />
        <TextInput
          maxLength={1}
          ref={secondRef}
          style={styles.input}
          textAlign='center'
          keyboardType='numeric'
          onKeyPress={(e) => {
            const isBack = onKeyPress(e);
            if(isBack) {
              firstRef.current.focus();
            }
          }}
          onChangeText={(t: string) => {
            if(!t) return;
            console.log("Second: ", t)
            thirdRef.current.focus();
          }}
        />
        <TextInput
          maxLength={1}
          ref={thirdRef}
          style={styles.input}
          textAlign='center'
          keyboardType='numeric'
          onKeyPress={(e) => {
            const isBack = onKeyPress(e);
            if(isBack) {
              secondRef.current.focus();
            }
          }}
          onChangeText={(t: string) => {
            if(!t) return;
            console.log("Third: ", t)
            fourthRef.current.focus();
          }}
        />
        <TextInput
          maxLength={1}
          ref={fourthRef}
          style={styles.input}
          textAlign='center'
          keyboardType='numeric'
          onKeyPress={(e) => {
            const isBack = onKeyPress(e);
            if(isBack) {
              thirdRef.current.focus();
            } else {
              fourthRef.current.focus();
              fourthRef.current.blur();
            }
          }}
          onChangeText={(t: string) => {
            if(!t) return;
            console.log("Fourth: ", t)
          }}
        />
      </View>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    margin: 10,
    gap: 20
  },
  input: {
    width: 50,
    height: 50,
    borderColor: 'blue',
    borderWidth: 1,
    borderRadius: 50,
    padding: 10,
    fontSize: 20,
    color: 'black',
  },
  text: {
    fontSize: 15,
    color: 'black',
    fontStyle: 'italic'
  },
  block: {
    flexGrow: 1,
    flexDirection: 'row',
    gap: 10,
    justifyContent: 'center'
  }
});

Share is Caring

Related Posts