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

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.

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..

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,

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'
}
});