Learn how to get the position of the cursor within a text box or a text area easily with Backward browser compatibility in Javascript.

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 and end 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 !


Senior Software Engineer at Software Medico. Interested in programming since he was 14 years old, Carlos is a self-taught programmer and founder and author of most of the articles at Our Code World.

Sponsors