Cross-browser library for calculating precise pixel coordinates of textarea and input caret positions
npx @tessl/cli install tessl/npm-textarea-caret@3.1.0Cross-browser JavaScript library that calculates precise pixel coordinates of the text caret (cursor) position in HTML textarea and input elements. Uses an invisible mirror div technique to replicate element styling and determine exact caret positioning for building sophisticated text input interfaces.
npm install textarea-caretconst getCaretCoordinates = require('textarea-caret');For ES modules:
import getCaretCoordinates from 'textarea-caret';Browser (global with UMD pattern):
<script src="path/to/textarea-caret/index.js"></script>
<script>
// Function available as window.getCaretCoordinates
</script>const getCaretCoordinates = require('textarea-caret');
// Get caret coordinates for a textarea
const textarea = document.querySelector('textarea');
textarea.addEventListener('input', function() {
const caret = getCaretCoordinates(this, this.selectionEnd);
console.log(`Caret at (${caret.left}, ${caret.top}) with height ${caret.height}px`);
});
// Get caret coordinates for an input
const input = document.querySelector('input[type="text"]');
const position = input.selectionStart;
const coordinates = getCaretCoordinates(input, position);
// Position a dropdown at the caret
const dropdown = document.getElementById('autocomplete');
dropdown.style.position = 'absolute';
dropdown.style.left = coordinates.left + 'px';
dropdown.style.top = (coordinates.top + coordinates.height) + 'px';Calculates the precise pixel coordinates of the text caret position in textarea and input elements.
/**
* Calculate pixel coordinates of text caret position in textarea/input elements
* @param element - HTML element (must be textarea or input type="text")
* @param position - Integer caret position (typically selectionStart or selectionEnd)
* @param options - Optional configuration object
* @returns Object with top, left, and height properties in pixels
*/
function getCaretCoordinates(element, position, options);Parameters:
element (HTMLElement, required): DOM element - must be <textarea> or <input type="text">position (number, required): Integer caret position (0-based index into the text content)options (object, optional): Configuration object with the following properties:
debug (boolean): If true, keeps the mirror div visible for debugging purposes (default: false)Return Value:
interface CaretCoordinates {
/** Offset in pixels from element's top edge (including border) */
top: number;
/** Offset in pixels from element's left edge (including border) */
left: number;
/** Height of the caret in pixels (typically the line height) */
height: number;
}Advanced Features:
Usage Examples:
// Basic autocomplete positioning
function showAutocomplete(textarea) {
const position = textarea.selectionStart;
const coords = getCaretCoordinates(textarea, position);
const dropdown = document.getElementById('autocomplete');
dropdown.style.left = coords.left + 'px';
dropdown.style.top = (coords.top + coords.height + 2) + 'px';
dropdown.style.display = 'block';
}
// Mention system (@username)
function handleAtMention(textarea) {
const text = textarea.value;
const cursorPos = textarea.selectionStart;
// Find @ symbol before cursor
const atIndex = text.lastIndexOf('@', cursorPos - 1);
if (atIndex !== -1) {
const coords = getCaretCoordinates(textarea, cursorPos);
showMentionDropdown(coords.left, coords.top + coords.height);
}
}
// Debug mode to visualize the mirror div
function debugCaretPosition(element, position) {
const coords = getCaretCoordinates(element, position, { debug: true });
console.log('Caret coordinates:', coords);
// Mirror div remains visible with highlighted caret position
}
// Input field with floating label
function updateFloatingLabel(input) {
const coords = getCaretCoordinates(input, input.selectionStart);
const label = document.getElementById('floating-label');
if (input.value.length > 0) {
label.style.left = coords.left + 'px';
label.style.top = (coords.top - 20) + 'px';
}
}Error Handling:
The function throws an error if called in a non-browser environment:
// Throws: 'textarea-caret-position#getCaretCoordinates should only be called in a browser'
try {
const coords = getCaretCoordinates(element, position);
} catch (error) {
console.error('Must be called in browser environment:', error.message);
}Browser Compatibility:
Known Limitations:
The library works by creating an invisible mirror div that exactly replicates the styling of the target element:
<div> positioned off-screen with identical styling<span> at the caret position with remaining textThis technique ensures pixel-perfect accuracy across different browsers and styling configurations.