Sometimes it is nice to be able to insert the cursor at a specific location within a textbox. The most common purpose for this, in my opinion, is with textareas. For a theoretical example, I will explain a scenario I have run into a few times. I have already typed a paragraph into a textarea for comments, a message, whatever. For whatever reason, I go back up on the form and change a different field, and then tab back down to the text area. By default, it highlights the whole body of text within the textarea. But, I wanted to append some text what was there! Now I either have to grab my mouse and click at the end of the box or use a series of keystrokes to get the caret back to where I need it.
Ok fine, so maybe I am getting way too particular here. But it really is a minor annoyance to me. Granted, I could easily live with it, but I have come up with a solution instead. It would be best (again, this is my opinion) to programmatically force the cursor to jump to the end of the text area when it receives focus. I would not disagree that in some cases it can be rather convienent to have it it highlight the value on focus. But, for textareas, I just can not agree with it.
Anyways, that is how I got around to creating this generic function that will allow you to insert the caret at any position of a textbox or textarea that you wish...
function setCaretPosition(elemId, caretPos) { var elem = document.getElementById(elemId); if(elem != null) { if(elem.createTextRange) { var range = elem.createTextRange(); range.move('character', caretPos); range.select(); } else { if(elem.selectionStart) { elem.focus(); elem.setSelectionRange(caretPos, caretPos); } else elem.focus(); } } }
The first expected parameter is the ID of the element you wish to insert the cursor on. If the element is unable to be found, nothing will happen (obviously). The second parameter is the caret positon index. Zero will put the cursor at the beginning. If you pass a number larger than the number of characters in the elements value, it will put the cursor at the end.
I have tested it on several browsers; it works beautifully on IE6 and up, Firefox 2, Opera 8, Netscape 9, SeaMonkey, and Safari. Unfortunately on Safari it does not work in combination with the onfocus event (sigh). If anybody out there has quick access to some older browsers (or any browser not mentioned above) and a few moments to test it, I'd really appreciate it if you let me know if it works or not.
Keep in mind that the above function could potentially be used for several different purposes. Even though my original purpose was somewhat impractical, there is definite potential for this function! Here is the unobtrusive example of using it to apply my original purpose: force the cursor to jump to the end of all textareas on the page when they receive focus...
function addLoadEvent(func) { if(typeof window.onload != 'function') { window.onload = func; } else { if(func) { var oldLoad = window.onload; window.onload = function() { if(oldLoad) oldLoad(); func(); } } } } // The setCaretPosition function belongs right here! function setTextAreasOnFocus() { /*** * This function will force the cursor to be positioned * at the end of all textareas when they receive focus. */ var textAreas = document.getElementsByTagName('textarea'); for(var i = 0; i < textAreas.length; i++) { textAreas[i].onfocus = function() { setCaretPosition(this.id, this.value.length); } } textAreas = null; } addLoadEvent(setTextAreasOnFocus);
I am going to make an effort to include an unobtrusive example with all of my javascript related posts from here on out. Too many people are using inline attributes in the markup to trigger Javascript these days. It's undoubtedly wiser to do it the unobtrusive way for many reasons. The script degrades gracefully, will be easier to maintain, and will further separate behavioral logic from markup. All you have to do is bring javascript file into the markup (with <script> tags in the <head> section) and watch it work. If you want to learn more about unobtrusive javascript and its benefits, see the wonderful List Apart article by Jeremy Keith.
I hope somebody finds this useful!
However, you say that the script works beautifully on various browsers, including Safari. But when I run your script in Safari it appears in all cases to position the cursor before te first character in the text box. Am I missing something?
Thanks
John Elder
Good catch! Thanks for letting me know.
Safari has some good things going for it - principally speed of rendering (its Javascript and rendering engines are faster than Firefox and Explorer) and general aesthetics. But they do at times seem to lag behind in terms of complete implemention of all of the W£C various standards. But then, Explorer is the most guilty of all in this respect
But what happened if teh selection is outside the viewport of the textarea. I mean I am looking for line 10 and I am in line 200, for example...
To workaround this, try using a setTimeout(function(){element.select();},0); to open a new "thread" and allow the select method to be outside of the focus!
Guess What?
There are a few basic guidelines you should be aware of before leaving a comment…
- If you choose to display your email address, it will not be detected by spam bots
- Comments are limited to 3,000 characters; so far you have used none of them
- HTML will be encoded; links and line breaks will be converted automatically
- Comments containing five or more links will be subject to moderation
