ifelsething logoifelsething

Change Cursor Position of React Native Text Input

Posted By: Harish
Change Cursor Position of React Native Text Input

If you are in a situation where you need to programmatically change the position of the react native’s text input cursor, then this post can help you.

We can change the cursor position using the selection prop of text input. But with that prop, we need other implementations to completely get the correct behavior.

Lets see an implementation,

Create A New Project

Create a new react-native project by using npx. Check documentation for creating a new react native project.

npx react-native@latest init TextInputRN

Import TextInput Component

Import TextInput component and add basic props to it.

//app.tsx
import {
  StyleSheet,
  TextInput,
} from "react-native";

...
<TextInput
  style={styles.input}
  keyboardType='default'
  placeholder="Enter text"
  placeholderTextColor='gray'
  autoFocus={true}
  showSoftInputOnFocus={true}
  autoCorrect={false}
/>
...

Now comes the main part, selection prop.

Selection prop lets users select the value inside the text input programmatically. This prop takes start and end position values to select the text.

If we give the same position numbers to start and end, this behaves as a way to change the cursor position. If we give different positions, then characters between those numbers will be selected.

Add selection prop with a start and end values as an object. We are using a Button with useState to set the position on tap.

import { useRef, useState } from "react";
import {
  StyleSheet,
  TextInput,
  Button
} from "react-native";

...

type PositionType = {
  start: number,
  end: number
}

...

export const CursorPosition = () => {
  const [position, setPosition] = useState<PositionType>();
  ...
  return (
   ...
   <TextInput
     ...
     selection={position}
   />
   <Button
     title="Change cursor position to 8"
     onPress={() => {
       setPosition({ start: 8, end: 8 })
     }}
   />
  )

Now run the app, enter some text and press the button to change the position.

#for Android
npx react-native run-android

#for ios
npx react-native run-ios

After tapping the button, you can see that the entered text is gone and on typing further, position is set to 0 and text will get cleared automatically.

Change Cursor Position of React Native Text Input

This is because, after we set the cursor position using selection prop, text input is getting re--rendered and the entered text is cleared automatically for every re-render.

So, we need to save the text value in a state so that it stays even after re-render.

Create a state value and setState value returned from onChangeText callback. This callback returns the input value with every keystroke.

Now re-run the app.


...
const [value, setValue] = useState<string>();
...

<TextInput
  ...
  selection={position}
  value={value}
  onChangeText={setValue}
/>
...

You will notice that the cursor will be at a new position. But if you enter text at the new position, text will be in reverse order..

Change Cursor Position of React Native Text Input

As we set the new cursor position, it remains the same even after we enter a character which results in reverse ordered text.

To overcome this, we have to set the current position to selection prop to get the normal behavior.

To get the current cursor position, we can use the onSelectionChanged callback which returns an event with the current cursor position.

...
<TextInput
  ...
  onSelectionChanged={(e: NativeSyntheticEvent<TextInputSelectionChangeEventData>) => {
    const newPosition = e.nativeEvent.selection;
    console.log("New Cursor Position: ", newPosition);
  }}
/>
...

We have to use this current position to update the selection prop value. Set the received position value of onSelectionChanged callback to position state.

...
<TextInput
  ...
  onSelectionChanged={(e: NativeSyntheticEvent<TextInputSelectionChangeEventData>) => {
     const newPosition = e.nativeEvent.selection;
     setPosition(newPosition);
  }}
/>
...

If we re-run the app, we can see that the new position is being set on tap of a button and typing further results will be without any reverse order.

Check below gif,

Change Cursor Position of React Native Text Input

Complete code of our example,

//App.tsx
import { useState } from "react";
import {
  View,
  Text,
  StyleSheet,
  TextInput,
  Button
} from "react-native";

type PositionType = {
  start: number,
  end: number
}

export const App = () => {
  const [position, setPosition] = useState<PositionType>();
  const [value, setValue] = useState<string>();
  const changePosition = (newPosition: number) => {
    setPosition({
      start: newPosition,
      end: newPosition
    });
  }
  return (
    <View style={styles.container} >
      <Text style={styles.text}>
        ifelsething.com
      </Text>
      <Text style={styles.text}>
        Change cursor position of text input
      </Text>
      <TextInput
        style={styles.input}
        keyboardType='default'
        placeholder="Enter text"
        placeholderTextColor='gray'
        value={value}
        selection={position}
        onSelectionChange={(e) => {
          const selection = e.nativeEvent.selection;
          setPosition(selection)
        }}
        onChangeText={setValue}
        autoFocus={true}
        showSoftInputOnFocus={true}
        autoCorrect={false}
      />
      <Button
        title="Change cursor position to 8"
        onPress={() => {
          changePosition(8);
        }}
      />
      <Button
        title="Back to normal position"
        onPress={() => {
          if (!value) return;
          changePosition(value.length);
        }}
      />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    margin: 10,
    gap: 20,
  },
  input: {
    borderColor: 'blue',
    borderWidth: 1,
    borderRadius: 10,
    padding: 10,
    fontSize: 15,
    color: 'black',
  },
  text: {
    fontSize: 15,
    color: 'black',
    fontStyle: 'italic'
  }
});

Share is Caring

Related Posts