37

I am using jQuery and trying to find a cross browser way to get the pixel coordinates of the caret in <textarea>s and input boxes such that I can place an absolutely positioned div around this location.

Is there some jQuery plugin? Or JavaScript snippet to do just that?

Dan Dascalescu
  • 143,271
  • 52
  • 317
  • 404
Pat
  • 36,282
  • 18
  • 72
  • 87

2 Answers2

44

I've looked for a textarea caret coordinates plugin for meteor-autocomplete, so I've evaluated all the 8 plugins on GitHub. The winner is, by far, textarea-caret-position from Component.

Features

  • pixel precision
  • no dependencies whatsoever
  • browser compatibility: Chrome, Safari, Firefox (despite two bugs it has), IE9+; may work but not tested in Opera, IE8 or older
  • supports any font family and size, as well as text-transforms
  • the text area can have arbitrary padding or borders
  • not confused by horizontal or vertical scrollbars in the textarea
  • supports hard returns, tabs (except on IE) and consecutive spaces in the text
  • correct position on lines longer than the columns in the text area
  • no "ghost" position in the empty space at the end of a line when wrapping long words

Here's a demo - http://jsfiddle.net/dandv/aFPA7/

enter image description here

How it works

A mirror <div> is created off-screen and styled exactly like the <textarea>. Then, the text of the textarea up to the caret is copied into the div and a <span> is inserted right after it. Then, the text content of the span is set to the remainder of the text in the textarea, in order to faithfully reproduce the wrapping in the faux div.

This is the only method guaranteed to handle all the edge cases pertaining to wrapping long lines. It's also used by GitHub to determine the position of its @ user dropdown.

Dan Dascalescu
  • 143,271
  • 52
  • 317
  • 404
  • 3
    I just noticed that in-between the "ranodm" text, you have the lyrics of the song by Carly Rae Jepsen - Call Me Maybe (http://www.youtube.com/watch?v=fWNaR-rxAic). But nice suggestion! However, it has a bug on recent Chrome versions. You select from the start of a line until the middle. Then you click on the beggining of the line. The red line won't move. – Ismael Miguel Jan 20 '15 at 11:19
  • @IsmaelMiguel - Glad you noticed the song :) As for the issue, can you please [file it on GitHub](https://github.com/component/textarea-caret-position/issues)? Thanks! – Dan Dascalescu Jan 21 '15 at 01:33
  • I just noticed now. I misspelled random :/ And I have more bad news: ghost selection is back on IE11. – Ismael Miguel Jan 21 '15 at 09:24
  • doesn't work for me, i just opened the demo jsfiddle, click somewhere around the middle and the caret seems to be off by 1 line – stenwolf Oct 03 '19 at 00:01
1

Note: this answer describes how to get the character co-ordinates of the text-cursor/caret. To find the pixel-co-ordinates, you'll need to extend this further.

The first thing to remember is that the cursor can be in three states

  • a regular insertion cursor at a specific position
  • a text selection that has a certain bounded area
  • not active: textarea does not have focus. Has not been used.

The IE model uses the Object document.selection, from this we can get a TextRange object which gives us access to the selection and thus the cursor position(s).

The FF model/Opera uses the handy variables [input].selectionStart and selectionEnd.

Both models represent a regular ative cursor as a zero-width selection, with the left bound being the cursor position.

If the input field does not have focus, you may find that neither is set. I have had good success with the following code to insert a piece of text at the current cursor location, also replacing the current selection, if present. Depending on the exact browser, YMMV.

function insertAtCursor(myField, myValue) {

/* selecion model - ie */
if (document.selection) {
  myField.focus();
  sel = document.selection.createRange();
  sel.text = myValue;
}

/* field.selectionstart/end  firefox */ 
else if (myField.selectionStart || myField.selectionStart == '0' ) {

  var startPos = myField.selectionStart;
  var endPos = myField.selectionEnd;
  myField.value = myField.value.substring(0, startPos)
    + myValue
    + myField.value.substring(endPos, myField.value.length);

  myField.selectionStart = startPos + myValue.length;
  myField.selectionEnd = startPos + myValue.length;
  myField.focus();
} 

// cursor not active/present
else {
  myField.value += myValue;
}

Bug Note: links are not being correctly marked up in the top para.

Selection object: http://msdn.microsoft.com/en-us/library/ms535869(VS.85).aspx
TextRange object: http://msdn.microsoft.com/en-us/library/ms535872(VS.85).aspx

Cheekysoft
  • 35,194
  • 20
  • 73
  • 86
  • The **Component.io** team has developed [a plugin](http://stackoverflow.com/a/22446703/1269037) to calculate the (x, y) coordinates of the caret in a `textarea`. It works almost perfectly, except for [an issue with IE](https://github.com/component/textarea-caret-position/issues/14). Might you be able to help? – Dan Dascalescu Mar 17 '14 at 11:26