text-input-cursor
An Expo module for retrieving the on-screen coordinates of the text cursor in TextInput components. This module enables precise positioning of UI elements such as autocomplete dropdowns, mention suggestions, and tooltips relative to the cursor position.
Installation
npm install text-input-cursor
or
yarn add text-input-cursor
Demo
Usage
Standard Mode
The TextInputWithCursor component provides automatic cursor tracking with real-time coordinate updates on every text change.
import { useState } from 'react';
import { View, StyleSheet } from 'react-native';
import { TextInputWithCursor, type CursorCoordinates } from 'text-input-cursor';
export default function Example() {
const [text, setText] = useState('');
const [cursorCoords, setCursorCoords] = useState<CursorCoordinates | null>(null);
return (
<View style={styles.container}>
<View>
<TextInputWithCursor
value={text}
onChangeText={setText}
onCursorCoordinatesChange={({ coordinates }) => {
setCursorCoords(coordinates);
}}
placeholder="Type @ to mention someone..."
multiline
style={styles.input}
/>
{cursorCoords && (
<View
style={[
styles.dropdown,
{
top: cursorCoords.y,
left: cursorCoords.x,
}
]}
>
{/* Your dropdown content */}
</View>
)}
</View>
</View>
);
}
Performance Mode
For performance-critical applications, use getCursorCoordinates to fetch coordinates only when needed. This approach eliminates unnecessary calculations during normal typing and only queries cursor position when specific triggers are detected.
import { useState, useRef } from 'react';
import { View, TextInput } from 'react-native';
import { getCursorCoordinates, type CursorCoordinates } from 'text-input-cursor';
export default function PerformanceExample() {
const [text, setText] = useState('');
const [cursorCoords, setCursorCoords] = useState<CursorCoordinates | null>(null);
const inputRef = useRef<TextInput>(null);
const handleTextChange = async (newText: string) => {
setText(newText);
if () {
const coords = await getCursorCoordinates(inputRef);
setCursorCoords(coords);
} else {
setCursorCoords(null);
}
};
return (
<View style={styles.container}>
<View>
<TextInput
ref={inputRef}
value={text}
onChangeText={handleTextChange}
placeholder="Type @ to mention someone..."
multiline
style={styles.input}
/>
{cursorCoords && (
<View
style={[
styles.dropdown,
{
top: cursorCoords.y,
left: cursorCoords.x,
}
]}
>
{/* Your dropdown content */}
</View>
)}
</View>
</View>
);
}
Important: Coordinate Positioning
The returned coordinates (x, y) are relative to the TextInput component, not the screen. To position elements correctly:
- Wrap the TextInput and positioned elements in a common parent View
- Use
position: 'absolute' on the positioned element
- Apply the coordinates directly to the element's
top and left style properties
The parent View establishes the coordinate space for both the TextInput and the absolutely positioned element. Make sure the parent View doesn't have a padding.
API Reference
TextInputWithCursor
A component that extends React Native's TextInput with automatic cursor tracking.
Props
- All standard
TextInput props
onCursorCoordinatesChange?: (event: CursorCoordinatesChangeEvent) => void
CursorCoordinatesChangeEvent
{
coordinates: CursorCoordinates | null;
cursorPosition: number;
}
getCursorCoordinates
Function to retrieve cursor coordinates on demand.
function getCursorCoordinates(
inputRef: RefObject<TextInput>
): Promise<CursorCoordinates | null>
CursorCoordinates
{
x: number;
y: number;
lineHeight: number;
}
Returns null if the input reference is unavailable, platform is unsupported, or an error occurs.
Platform Support
Implementation Details
This module uses native platform APIs for accurate cursor positioning. Improvements and suggestions are welcome!
- iOS:
UITextView.caretRect(for:) and UITextField.caretRect(for:)
- Android:
Layout.getPrimaryHorizontal(), Layout.getLineTop(), and Layout.getLineBottom()
- Web: Shadow element technique that creates an invisible mirror div with identical styles and text content, using
getBoundingClientRect() on a span element to measure the exact cursor position
License
MIT