Get caret position in HTML input?
Asked Answered
W

6

72

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

Wainscoting answered 8/2, 2011 at 1:6 Comment(0)
H
54

-> 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>
Hawsehole answered 8/2, 2011 at 2:12 Comment(6)
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.Hakenkreuz
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.Lawannalawbreaker
if you use keydown, then you need to adjust the output based on whether or not the key is an arrow keyPhylogeny
@Hakenkreuz 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 trickPhylogeny
@Phylogeny 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.Hakenkreuz
@Hakenkreuz yep i was aware of that. thanks for pointing it out nonetheless!Phylogeny
A
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 ); 
Arguello answered 8/2, 2011 at 10:34 Comment(3)
@NadavB: Are you sure the value you're passing into the function is a DOM input or textarea element?Arguello
@TimDown it's content editable div. Should it work on it too?Invalidate
@NadavB: No. Here's a rough equivalent for contenteditable: https://mcmap.net/q/83470/-get-a-range-39-s-start-and-end-offset-39-s-relative-to-its-parent-containerArguello
O
9

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

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

Obala answered 29/1, 2014 at 10:30 Comment(0)
A
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;
}
Aimless answered 8/2, 2011 at 2:21 Comment(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/Tophet
F
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

Flinders answered 23/2, 2022 at 18:14 Comment(0)
P
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);
}
Pipeline answered 18/3, 2019 at 10:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.