Retrieve the position of the cursor (caret) within a textarea is easier than you think. Although you won't get a property named "cursorPosition
" or "caretPosition
", you can deduct this value from the selectionStart
property from the element which is basically the same. These values (start and end) provide always an integer value with the index of the selected text within a textarea or text input. In case that not any text is selected, those values (start and end) will be the same, which means that they're equivalent to the position of the cursor in the element.
The typical way
Every textarea and text input, should have available the selectionStart
and selectionEnd
properties which contains the character index of the start position of the selection and the character index of the end position of the selection respectively.
<input type="text" id="text-element" />
<!-- Or a textarea
<textarea id="text-element"></textarea>
-->
<input type="button" id="trigger" value="Check"/>
<script>
document.getElementById("trigger").addEventListener("click", function(){
var myElement = document.getElementById('text-element');
var startPosition = myElement.selectionStart;
var endPosition = myElement.selectionEnd;
// Check if you've selected text
if(startPosition == endPosition){
alert("The position of the cursor is (" + startPosition + "/" + myElement.value.length + ")");
}else{
alert("Selected text from ("+ startPosition +" to "+ endPosition + " of " + myElement.value.length + ")");
}
},false);
</script>
The method will work independently of the kind of element (input text or textarea) on every modern browser.
IE < 8 support
Pitifully, the Internet Explorer Browser < 8 doesn't provide support for the selectionStart
and selectionEnd
properties, therefore we need to workaround this using a text range without seriously compromise the performance.
In order to provide support for old browsers, use the following method. The method is asynchronous, it expects as first parameter a DOM element (wheter textarea or text input) and it will return an object with 2 properties (start and end equivalent to the values of selectionStart
and selectionEnd
).
/**
* Return an object with the selection range or cursor position (if both have the same value)
* @param {DOMElement} el A dom element of a textarea or input text.
* @return {Object} reference Object with 2 properties (start and end) with the identifier of the location of the cursor and selected text.
**/
function getInputSelection(el) {
var start = 0, end = 0, normalizedValue, range, textInputRange, len, endRange;
if (typeof el.selectionStart == "number" && typeof el.selectionEnd == "number") {
start = el.selectionStart;
end = el.selectionEnd;
} else {
range = document.selection.createRange();
if (range && range.parentElement() == el) {
len = el.value.length;
normalizedValue = el.value.replace(/\r\n/g, "\n");
// Create a working TextRange that lives only in the input
textInputRange = el.createTextRange();
textInputRange.moveToBookmark(range.getBookmark());
// Check if the start and end of the selection are at the very end
// of the input, since moveStart/moveEnd doesn't return what we want
// in those cases
endRange = el.createTextRange();
endRange.collapse(false);
if (textInputRange.compareEndPoints("StartToEnd", endRange) > -1) {
start = end = len;
} else {
start = -textInputRange.moveStart("character", -len);
start += normalizedValue.slice(0, start).split("\n").length - 1;
if (textInputRange.compareEndPoints("EndToEnd", endRange) > -1) {
end = len;
} else {
end = -textInputRange.moveEnd("character", -len);
end += normalizedValue.slice(0, end).split("\n").length - 1;
}
}
}
}
return {
start: start,
end: end
};
}
You can use it easily using the previous function (remember to focus the input using the focus method to prevent any error):
var element = document.getElementById("someID");
// Focus element, in case that it's not
element.focus();
var result = getInputSelection(element);
console.log(result);
// {
// start: 5,
// end: 5
// }
And see a live example in the following fiddle:
The previous snippet was published in StackOverflow and the one who answered, created a repository with MIT license. The mini library is a wrapper made in jQuery for tipical tasks related to the text selection and position within a text input or textarea element (getSelection, setSelection, deleteText etc).
Conclusions
- If the
start
andend
value are the same, it means that there's no selected text and the start value (or end value) is the position of the cursor. - Note that in IE the textarea or text input must have the focus before calling the mentioned method. You can ensure this by calling the
focus()
method of the element (or its jQuery object).
Have fun !