Finding selection start and end position in a textarea, in Internet Explorer
Published June 29th, 2005[UPDATED 1st July 2005 -- a better method!]
I’m sure I’m missing something obvious here — I’m sure this can’t be true. If you can put me out of my misery then please do so. In the meantime…
I want to get the start and end positions of selected text in a TEXTAREA element. I don’t mean I want to manipulate the contents of the selection — you can do that easily like this:
document.selection.createRange().text = 'Some new text';
I need to know where in a piece of text the selection begins and ends. It’s easy enough in Mozilla: element.selectionStart and element.selectionEnd do the trick.
In IE, you can get just about every other bit of information you could possibly want — the position and size of the selection in pixels, for example — but not the start and end points of the selection. Bonkers.
I tried a number of ideas, and ended up with (yet another) ugly but functional fix. It goes like this:
- Use document.selection.createRange() to get the current selection
- Create a duplicate of that range with textRange.duplicate()
- Use range.moveToElementText() to select all text in the duplicate range
- Now use textRange.setEndPoint() to move the end of the range to the same place as the original range (ie. the original end point of the selection)
- Subtract the length of the original selection from the length of the new selection, to get the start point of the original selection
- Add the length of the original selection to the newly-calculated start point, to get the end point
Phew! Way too complicated for what should be a simple operation, but it does work.
Here’s some code:
var element = document.getElementById( 'my_textarea' );
if( document.selection ){
// The current selection
var range = document.selection.createRange();
// We'll use this as a 'dummy'
var stored_range = range.duplicate();
// Select all text
stored_range.moveToElementText( element );
// Now move 'dummy' end point to end point of original range
stored_range.setEndPoint( 'EndToEnd', range );
// Now we can calculate start and end points
element.selectionStart = stored_range.text.length - range.text.length;
element.selectionEnd = element.selectionStart + range.text.length;
}
Because this sets the selectionStart and selectionEnd properties for the element, you can use the same methods for getting/setting selection contents as you would for Mozilla.
I made extensive use of this Microsoft reference page to work all this stuff out.
Rafi B. on August 4, 2005
Thank you for posting this helpful tip.
I’ve been trying to use it on the input type=”text” element,
but with no success. Is this just for a textarea element?
I’ve found a solution though:
function getCaretPos(el) {
if (typeof el.selectionStart != “undefined”)
return el.selectionStart;
else if (document.selection)
return Math.abs(document.selection.createRange().moveStart(”character”, -1000000));
}
Ratty on August 25, 2005
This code seems to stop keyboard navigation working. ie. pressing the arrows to move around the text box do nothing. is there a fix for this?
Ratty on August 25, 2005
Sorry, I was wrong. It was my fault for only testing it under Wine in Linux. Works perfectly in Windows. Thanks dude
ike on September 6, 2005
well, your solution doesn`t work if i apply it to a body of a html… it goes close but….not close enough! the region seems shifted by a few characters. if the body does not have tags it works wonderfully but i need a solution for full html documents. any ideas? i`ve tried to eliminate the tags from region.htmlText and count it like that but it still doesn`t work. i`m desperate.
Sebastian Werner on September 29, 2005
The length of the current selection you can get from:
document.selection.createRange().text.length;
Then you only need to detect where the start point is, to get the matching end.
var yourrange = yourtextfield.createTextRange();
yourrange.setEndPoint(”EndToStart”, document.selection.createRange());
var yourselstart = yourrange.text.length;
Just my two cents. But your solution is not so much different.
Sébastien CRAMATTE on November 6, 2005
I need to handle selection with IE on keyPress event ? have you got an idea or some code snippet ?
Tobias on December 11, 2005
The shown code only works for textareas but not for input fields of type ‘text’. Therefore, the line
“stored_range.moveToElementText( element );”
can be replaced by
“stored_range.expand(’textedit’);”
This works for me
Abhishek Iyer on December 29, 2005
Pity that there couldnt be a simpler soln. In the meantime , might i add that this shlould be handled in “onMouseDown” else you might loose the selection. Great work StickMan!
suraj on April 21, 2006
this guy is the fucking MAN! fucking LIFE SAVER…
p.s. - these security codes are REALLY TOO difficult to read :S
suraj on April 21, 2006
after experimenting, this code seems to struggle in textareas…
For the first line - it works fine to reposition the caret however, as you move further down the textarea it runs into problems and adds the caret to a silly position
Stine on August 3, 2006
Hi:) This seems to work for me:
function js_countTextAreaChars(text) {
var n = 0;
for (var i = 0; i
Stine on August 3, 2006
Maybe it’s not possible to post more than a few lines? I’ll try again:
function js_countTextAreaChars(text) {
var n = 0;
for (var i = 0; i
Stine on August 3, 2006
function js_countTextAreaChars(text) {
var n = 0;
for (var i = 0; i
Stine on August 3, 2006
Well, I give up;)
Stine on August 3, 2006
function js_countTextAreaChars(text) {
var n = 0;
for (var i = 0; i < text.length; i++) {
if (text.charAt(i) != ‘\r’) {
n++;
}
}
return n;
}
function js_CursorPos(start, end) {
this.start = start;
this.end = end;
}
function js_getCursorPosition(textArea) {
var start = 0;
var end = 0;
if (document.selection) { // IE…
textArea.focus();
var sel1 = document.selection.createRange();
var sel2 = sel1.duplicate();
sel2.moveToElementText(textArea);
var selText = sel1.text;
sel1.text = “01″;
var index = sel2.text.indexOf(”01″);
start = js_countTextAreaChars((index == -1) ? sel2.text : sel2.text.substring(0, index));
end = js_countTextAreaChars(selText) + start;
sel1.moveStart(’character’, -1);
sel1.text = selText;
} else if (textArea.selectionStart || (textArea.selectionStart == “0″)) { // Mozilla/Netscape…
start = textArea.selectionStart;
end = textArea.selectionEnd;
}
return new js_CursorPos(start, end);
}
function js_setCursorPosition(textArea, cursorPos) {
if (document.selection) { // IE…
var sel = textArea.createTextRange();
sel.collapse(true);
sel.moveStart(”character”, cursorPos.start);
sel.moveEnd(”character”, cursorPos.end - cursorPos.start);
sel.select();
} else if (textArea.selectionStart || (textArea.selectionStart == “0″)) { // Mozilla/Netscape…
textArea.selectionStart = cursorPos.start;
textArea.selectionEnd = cursorPos.end;
}
textArea.focus();
}
Stine on August 3, 2006
There it is;)
Original Sin on November 23, 2006
Very sweet piece of code. I changed the Element to be a div tag, and it worked like a treat when combined with Javascript that fetches your selection. Thanks!
AmigoJack on November 28, 2006
Stines code doesnt work for me. it inserts “0″ into the text where my caret is. plus: if somewhere within the text “01″ occurs before, it doesnt work as expected of course
not to mention what will happen if the textarea isnt the only input on the document… *ARGH* the MSIE is really painful when it comes down on determining selection positions
Jayakrishnan G on April 16, 2007
What about licensing terms for using the above script.
Is the permission, to use this code, under the terms of GNU LGPL (www.gnu.org/licenses/lgpl.html) ?
roncli on May 3, 2007
AmigoJack,
- There’s a bug in Stine’s code. In the line — sel1.moveStart(’character’, -1); — the number “-1″ should be equal to zero minus the length of the dummy text. In the case of his code, the dummy text is “01″, so the number should be changed to “-2″.
- You don’t have to use “01″ as your dummy text, just change it to something that user’s won’t be likely to use, like “|pos|”, as the pipes aren’t something users often type in. Of course, you’d now have to change the “-1″ in my above point to the length of that dummy text, which is a three letter word plus two pipes… that makes it “-5″.
Tiny on May 4, 2007
quicker than Stine’s countTextAreaChars() one can, for textarea text say:
var iLen=text.length-text.split(’\r’).length-1;
This will account for IE’s funny way of *sometimes* counting \r
Also, instead of adding “01″ or “|pos|” try adding something truely obscure like
String.fromCharCode(28)
There is a character that your users will have a hard time typing! …And also, it works well for me. I’m not using Stine’s method, or even StickMan’s, but one like it. Since IE also insists on ignoring newlines that appear at the end of my text selections (anyone else experience that?) I’ve efforted to make sure there would be a non-newline at the end of my textarea, but also a character that would not confuse the user. I found decimal 28 (octal 34) to be good for that, then, I measure my positions from the end, because IE does count leading newlines.
if (oTextarea.value.charCodeAt(oTextarea.value.length-1) < 14) {
oTextarea.value=oTextarea.value.replace(/34/g,”)+String.fromCharCode(28);
}
var oRng = document.selection.createRange();
var oRng2 = oRng.duplicate();
oRng2.moveToElementText(oTextarea);
oRng2.setEndPoint(’StartToEnd’, oRng);
iEnd = oTextarea.value.length-oRng2.text.length;
oRng2.setEndPoint(’StartToStart’, oRng);
iStart = oTextarea.value.length-oRng2.text.length;
Tiny on May 5, 2007
by
var iLen=text.length-text.split(’\r’).length-1;
I of course meant
var iLen=text.length-(text.split(’\r’).length-1);
Tiny on May 5, 2007
and the regex
/34/g reads (let me try this again) /\34/g
Tiny on May 5, 2007
and trying one more time
/ \ 0 3 4 / g
(take out the spaces)
its too bad the comment preview doesn’t show us how special characters are handled.
Lázaro on August 16, 2007
Thanks for this solution. I spent many time in that Microsoft’s page, but I couldn’t find anything, unitl I “fall” here…thanks again.
arash on December 9, 2007
is there a solution to get cursor position coordinates in a input text html tag?
i have tooltip which should be always above the cursor. and where ever cursor moves (by typing,arrowkeys or mouse) it must move.
Vikrant Mohite on March 25, 2008
I want to split(”\n”) my textarea at charAt(50). can you guys help me out for the same.
Steve on May 6, 2008
Nice article, but your code ist difficult to read. Thanks for peoples for useful information
Stickman on May 6, 2008
Thanks for the heads-up, Steve. Looks like the ‘code’ tag I’ve been using doesn’t really work properly any more, for some reason. I’ve fixed the formatting for this article, now I need to find any other articles that have similar problems.
yohi on June 12, 2008
dear Stine,
your 15 th posting is very effective , but , when text area is having scroll box the code doesn’t focus on correct scroll position . plz give me a solution
thanks
yohi
nayana adassuriya on July 25, 2008
Thanks Stine, ur code is very use full, good work keep posting!!!!
Andrew on September 18, 2008
Thanks for this very useful function. I don’t know or even care how it works, but it works! Its ridiculous that ie doesn’t support selectionStart and selectionEnd properties.
anon on October 1, 2008
Solved elegantly at
http://www.webdeveloper.com/forum/archive/index.php/t-74982.html
m2pc
08-24-2005, 01:48 PM
var oSel = document.selection.createRange ();
// Move selection start to 0 position
oSel.moveStart (’character’, -oField.value.length);
// The caret position is selection length
iCaretPos = oSel.text.length;
Mau on October 16, 2008
Thank you so much for this trick. It works great for me.
Chreers!