70

How do I get the index of the text caret in an input?

Phrogz
  • 296,393
  • 112
  • 651
  • 745

6 Answers6

53

-> selectionStart

<!doctype html>
    
<html>
  <head>
    <meta charset = "utf-8">

    <script type = "text/javascript">
      window.addEventListener ("load", function () {
        var input = document.getElementsByTagName ("input");
        
        input[0].addEventListener ("keydown", function () {
          alert ("Caret position: " + this.selectionStart);
          
          // You can also set the caret: this.selectionStart = 2;
        });
      });
    </script>
    
    <title>Test</title>
  </head>

  <body>
    <input type = "text">
  </body>
</html>
Félix Paradis
  • 5,165
  • 6
  • 40
  • 49
Caio
  • 3,178
  • 6
  • 37
  • 52
  • 3
    Well, the listener should be registered on keyup and it does not handle new lines (textarea), but this does exactly what was asked for in modern browsers. – inta Dec 10 '12 at 15:39
  • You also need the input's selectionDirection to get the caret position whenever selectionDirection is backward i.e. you make a selection left-ward in the textbox so that selectionStart is the caret, but when selectionDirection is forward the caret will be at selectionEnd. – John Ernest Sep 29 '20 at 23:41
  • if you use `keydown`, then you need to adjust the output based on whether or not the `key` is an arrow key – oldboy Nov 06 '20 at 23:22
  • @inta is there any practical way to detect or anticipate the actual selection on the `keydown` event if one or more characters is highlighted or selected? just realized `selectionStart !== selectionEnd` should do the trick – oldboy Nov 06 '20 at 23:29
  • @oldboy yes that would work. Keep in mind, that the currently pressed key will not be included in your selection (for example if you select using shift+arrows). If you want to get the final selection use the "keyup" event. – inta Nov 09 '20 at 13:21
  • @inta yep i was aware of that. thanks for pointing it out nonetheless! – oldboy Nov 09 '20 at 23:08
32

The following will get you the start and end of the selection as character indices. It works for text inputs and textareas, and is slightly complicated because of IE's strange handling of line breaks.

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

var textBox = document.getElementById("textBoxId");
textBox.focus();
alert( getInputSelection(textBox).start ); 
Ashkan Mobayen Khiabani
  • 33,575
  • 33
  • 102
  • 171
Tim Down
  • 318,141
  • 75
  • 454
  • 536
9

There is now a nice jQuery plugin for this: Caret plugin

Then you can just call $("#myTextBox").caret();

Jens Mikkelsen
  • 2,712
  • 19
  • 23
7

We had used something like this for an old javascript application, but I haven't tested it in a couple years:

function getCaretPos(input) {
    // Internet Explorer Caret Position (TextArea)
    if (document.selection && document.selection.createRange) {
        var range = document.selection.createRange();
        var bookmark = range.getBookmark();
        var caret_pos = bookmark.charCodeAt(2) - 2;
    } else {
        // Firefox Caret Position (TextArea)
        if (input.setSelectionRange)
            var caret_pos = input.selectionStart;
    }

    return caret_pos;
}
Pandincus
  • 9,506
  • 9
  • 43
  • 61
  • 1
    Seems to be a consistent 21 characters off in IE. With an adjustment it seems fine there, but then is inaccurate in FF. [http://jsfiddle.net/zqNpV/](http://jsfiddle.net/zqNpV/) – stoicfury Jun 01 '12 at 18:14
6

Get coordinates (css: left:x , top:y) of the current caret position in order to position an element (e.g. show tooltip at caret position)

function getCaretCoordinates() {
  let x = 0,
    y = 0;
  const isSupported = typeof window.getSelection !== "undefined";
  if (isSupported) {
    const selection = window.getSelection();
    // Check if there is a selection (i.e. cursor in place)
    if (selection.rangeCount !== 0) {
      // Clone the range
      const range = selection.getRangeAt(0).cloneRange();
      // Collapse the range to the start, so there are not multiple chars selected
      range.collapse(true);
      // getCientRects returns all the positioning information we need
      const rect = range.getClientRects()[0];
      if (rect) {
        x = rect.left; // since the caret is only 1px wide, left == right
        y = rect.top; // top edge of the caret
      }
    }
  }
  return { x, y };
}

demo: https://codesandbox.io/s/caret-coordinates-index-contenteditable-9tq3o?from-embed

ref: https://javascript.plainenglish.io/how-to-find-the-caret-inside-a-contenteditable-element-955a5ad9bf81

GorvGoyl
  • 42,508
  • 29
  • 229
  • 225
2

Working example of getting cursor point in text box:

function textbox()
{
    var ctl = document.getElementById('Javascript_example');
    var startPos = ctl.selectionStart;
    var endPos = ctl.selectionEnd;
    alert(startPos + ", " + endPos);
}
Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
Bathri Nathan
  • 1,101
  • 2
  • 13
  • 17