javascript

html

jquery

textfield

How do you set the cursor position in a text field using jQuery? I've got a text field with content, and I want the users cursor to be positioned at a certain offset when they focus on the field. The code should look kind of like this:

$('#input').focus(function() {
  $(this).setCursorPosition(4);
});

What would the implementation of that setCursorPosition function look like? If you had a text field with the content abcdefg, this call would result in the cursor being positioned as follows: abcd**|**efg.

Java has a similar function, setCaretPosition. Does a similar method exist for javascript?

Update: I modified CMS's code to work with jQuery as follows:

new function($) {
  $.fn.setCursorPosition = function(pos) {
    if (this.setSelectionRange) {
      this.setSelectionRange(pos, pos);
    } else if (this.createTextRange) {
      var range = this.createTextRange();
      range.collapse(true);
      if(pos < 0) {
        pos = $(this).val().length + pos;
      }
      range.moveEnd('character', pos);
      range.moveStart('character', pos);
      range.select();
    }
  }
}(jQuery);

Solution 1

Here's a jQuery solution:

$.fn.selectRange = function(start, end) {
    if(end === undefined) {
        end = start;
    }
    return this.each(function() {
        if('selectionStart' in this) {
            this.selectionStart = start;
            this.selectionEnd = end;
        } else if(this.setSelectionRange) {
            this.setSelectionRange(start, end);
        } else if(this.createTextRange) {
            var range = this.createTextRange();
            range.collapse(true);
            range.moveEnd('character', end);
            range.moveStart('character', start);
            range.select();
        }
    });
};

With this, you can do

$('#elem').selectRange(3,5); // select a range of text
$('#elem').selectRange(3); // set cursor position

Solution 2

I have two functions:

function setSelectionRange(input, selectionStart, selectionEnd) {
  if (input.setSelectionRange) {
    input.focus();
    input.setSelectionRange(selectionStart, selectionEnd);
  }
  else if (input.createTextRange) {
    var range = input.createTextRange();
    range.collapse(true);
    range.moveEnd('character', selectionEnd);
    range.moveStart('character', selectionStart);
    range.select();
  }
}

function setCaretToPos (input, pos) {
  setSelectionRange(input, pos, pos);
}

Then you can use setCaretToPos like this:

setCaretToPos(document.getElementById("YOURINPUT"), 4);

Live example with both a textarea and an input, showing use from jQuery:

As of 2016, tested and working on Chrome, Firefox, IE11, even IE8 (see that last here; Stack Snippets don't support IE8).

Solution 3

The solutions here are right except for the jQuery extension code.

The extension function should iterate over each selected element and return this to support chaining. Here is the a correct version:

$.fn.setCursorPosition = function(pos) {
  this.each(function(index, elem) {
    if (elem.setSelectionRange) {
      elem.setSelectionRange(pos, pos);
    } else if (elem.createTextRange) {
      var range = elem.createTextRange();
      range.collapse(true);
      range.moveEnd('character', pos);
      range.moveStart('character', pos);
      range.select();
    }
  });
  return this;
};

Solution 4

I found a solution that works for me:

$.fn.setCursorPosition = function(position){
    if(this.length == 0) return this;
    return $(this).setSelection(position, position);
}

$.fn.setSelection = function(selectionStart, selectionEnd) {
    if(this.length == 0) return this;
    var input = this[0];

    if (input.createTextRange) {
        var range = input.createTextRange();
        range.collapse(true);
        range.moveEnd('character', selectionEnd);
        range.moveStart('character', selectionStart);
        range.select();
    } else if (input.setSelectionRange) {
        input.focus();
        input.setSelectionRange(selectionStart, selectionEnd);
    }

    return this;
}

$.fn.focusEnd = function(){
    this.setCursorPosition(this.val().length);
            return this;
}

Now you can move the focus to the end of any element by calling:

$(element).focusEnd();

Or you specify the position.

$(element).setCursorPosition(3); // This will focus on the third character.

Solution 5

This worked for me on Safari 5 on Mac OSX, jQuery 1.4:

$("Selector")[elementIx].selectionStart = desiredStartPos; 
$("Selector")[elementIx].selectionEnd = desiredEndPos;

Solution 6

I do realize that this is a very old post, but I thought that I should offer perhaps a simpler solution to update it using only jQuery.

function getTextCursorPosition(ele) {   
    return ele.prop("selectionStart");
}

function setTextCursorPosition(ele,pos) {
    ele.prop("selectionStart", pos + 1);
    ele.prop("selectionEnd", pos + 1);
}

function insertNewLine(text,cursorPos) {
    var firstSlice = text.slice(0,cursorPos);
    var secondSlice = text.slice(cursorPos);

    var new_text = [firstSlice,"\n",secondSlice].join('');

    return new_text;
}

Usage for using ctrl-enter to add a new line (like in Facebook):

$('textarea').on('keypress',function(e){
    if (e.keyCode == 13 && !e.ctrlKey) {
        e.preventDefault();
        //do something special here with just pressing Enter
    }else if (e.ctrlKey){
        //If the ctrl key was pressed with the Enter key,
        //then enter a new line break into the text
        var cursorPos = getTextCursorPosition($(this));                

        $(this).val(insertNewLine($(this).val(), cursorPos));
        setTextCursorPosition($(this), cursorPos);
    }
});

I am open to critique. Thank you.

UPDATE: This solution does not allow normal copy and paste functionality to work (i.e. ctrl-c, ctrl-v), so I will have to edit this in the future to make sure that part works again. If you have an idea how to do that, please comment here, and I will be happy to test it out. Thanks.

Solution 7

In IE to move cursor on some position this code is enough:

var range = elt.createTextRange();
range.move('character', pos);
range.select();

Solution 8

Solution 9

Set the focus before you have inserted the text into the textarea thus?

$("#comments").focus();
$("#comments").val(comments);

Solution 10

This works for me in chrome

$('#input').focus(function() {
    setTimeout( function() {
        document.getElementById('input').selectionStart = 4;
        document.getElementById('input').selectionEnd = 4;
    }, 1);
});

Apparently you need a delay of a microsecond or more, because usually a user focusses on the text field by clicking at some position in the text field (or by hitting tab) which you want to override, so you have to wait till the position is set by the user click and then change it.

Solution 11

Just remember to return false right after the function call if you're using the arrow keys since Chrome fricks the frack up otherwise.

{
    document.getElementById('moveto3').setSelectionRange(3,3);
    return false;
}

Solution 12

Based on this question, the answer will not work perfectly for ie and opera when there is new line in the textarea. The answer explain how to adjust the selectionStart, selectionEnd before calling setSelectionRange.

I have try the adjustOffset from the other question with the solution proposed by @AVProgrammer and it work.

function adjustOffset(el, offset) {
    /* From https://stackoverflow.com/a/8928945/611741 */
    var val = el.value, newOffset = offset;
    if (val.indexOf("\r\n") > -1) {
        var matches = val.replace(/\r\n/g, "\n").slice(0, offset).match(/\n/g);
        newOffset += matches ? matches.length : 0;
    }
    return newOffset;
}

$.fn.setCursorPosition = function(position){
    /* From https://stackoverflow.com/a/7180862/611741 */
    if(this.lengh == 0) return this;
    return $(this).setSelection(position, position);
}

$.fn.setSelection = function(selectionStart, selectionEnd) {
    /* From https://stackoverflow.com/a/7180862/611741 
       modified to fit https://stackoverflow.com/a/8928945/611741 */
    if(this.lengh == 0) return this;
    input = this[0];

    if (input.createTextRange) {
        var range = input.createTextRange();
        range.collapse(true);
        range.moveEnd('character', selectionEnd);
        range.moveStart('character', selectionStart);
        range.select();
    } else if (input.setSelectionRange) {
        input.focus();
        selectionStart = adjustOffset(input, selectionStart);
        selectionEnd = adjustOffset(input, selectionEnd);
        input.setSelectionRange(selectionStart, selectionEnd);
    }

    return this;
}

$.fn.focusEnd = function(){
    /* From https://stackoverflow.com/a/7180862/611741 */
    this.setCursorPosition(this.val().length);
}

Solution 13

Small modification to the code I found in bitbucket

Code is now able to select/highlight with start/end points if given 2 positions. Tested and works fine in FF/Chrome/IE9/Opera.

$('#field').caret(1, 9);

The code is listed below, only a few lines changed:

(function($) {
  $.fn.caret = function(pos) {
    var target = this[0];
    if (arguments.length == 0) { //get
      if (target.selectionStart) { //DOM
        var pos = target.selectionStart;
        return pos > 0 ? pos : 0;
      }
      else if (target.createTextRange) { //IE
        target.focus();
        var range = document.selection.createRange();
        if (range == null)
            return '0';
        var re = target.createTextRange();
        var rc = re.duplicate();
        re.moveToBookmark(range.getBookmark());
        rc.setEndPoint('EndToStart', re);
        return rc.text.length;
      }
      else return 0;
    }

    //set
    var pos_start = pos;
    var pos_end = pos;

    if (arguments.length > 1) {
        pos_end = arguments[1];
    }

    if (target.setSelectionRange) //DOM
      target.setSelectionRange(pos_start, pos_end);
    else if (target.createTextRange) { //IE
      var range = target.createTextRange();
      range.collapse(true);
      range.moveEnd('character', pos_end);
      range.moveStart('character', pos_start);
      range.select();
    }
  }
})(jQuery)

Solution 14

I had to get this working for contenteditable elements and jQuery and tought someone might want it ready to use:

$.fn.getCaret = function(n) {
    var d = $(this)[0];
    var s, r;
    r = document.createRange();
    r.selectNodeContents(d);
    s = window.getSelection();
    console.log('position: '+s.anchorOffset+' of '+s.anchorNode.textContent.length);
    return s.anchorOffset;
};

$.fn.setCaret = function(n) {
    var d = $(this)[0];
    d.focus();
    var r = document.createRange();
    var s = window.getSelection();
    r.setStart(d.childNodes[0], n);
    r.collapse(true);
    s.removeAllRanges();
    s.addRange(r);
    console.log('position: '+s.anchorOffset+' of '+s.anchorNode.textContent.length);
    return this;
};

Usage $(selector).getCaret() returns the number offset and $(selector).setCaret(num) establishes the offeset and sets focus on element.

Also a small tip, if you run $(selector).setCaret(num) from console it will return the console.log but you won't visualize the focus since it is established at the console window.

Bests ;D

Solution 15

You can directly change the prototype if setSelectionRange does not exist.

(function() {
    if (!HTMLInputElement.prototype.setSelectionRange) {
        HTMLInputElement.prototype.setSelectionRange = function(start, end) {
            if (this.createTextRange) {
                var range = this.createTextRange();
                this.collapse(true);
                this.moveEnd('character', end);
                this.moveStart('character', start);
                this.select();
            }
        }
    }
})();
document.getElementById("input_tag").setSelectionRange(6, 7);

jsFiddle link

Solution 16

As for me here the most easily way to add text(Tab -> \t) in textarea by cursor position and save the focus on cursor:

$('#text').keyup(function () {
    var cursor = $('#text').prop('selectionStart');
    //if cursot is first in textarea
    if (cursor == 0) {
        //i will add tab in line
        $('#text').val('\t' + $('#text').val());
        //here we set the cursor position
        $('#text').prop('selectionEnd', 1);
    } else {
        var value = $('#text').val();
        //save the value before cursor current position
        var valToCur = value.substring(0, cursor);
        //save the value after cursor current position
        var valAfter = value.substring(cursor, value.length);
        //save the new value with added tab in text
        $('#text').val(valToCur + '\t' + valAfter);
        //set focus of cursot after insert text (1 = because I add only one symbol)
        $('#text').prop('selectionEnd', cursor + 1);
    }
});