How to insert text into the textarea at the current cursor position?

JavascriptTextarea

Javascript Problem Overview


I would like to create a simple function that adds text into a text area at the user's cursor position. It needs to be a clean function. Just the basics. I can figure out the rest.

Javascript Solutions


Solution 1 - Javascript

Use selectionStart/selectionEnd properties of the input element (works for <textarea> as well)

function insertAtCursor(myField, myValue) {
    //IE support
    if (document.selection) {
        myField.focus();
        sel = document.selection.createRange();
        sel.text = myValue;
    }
    //MOZILLA and others
    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);
    } else {
        myField.value += myValue;
    }
}

Solution 2 - Javascript

This snippet could help you with it in a few lines of jQuery 1.9+: http://jsfiddle.net/4MBUG/2/

$('input[type=button]').on('click', function() {
    var cursorPos = $('#text').prop('selectionStart');
    var v = $('#text').val();
    var textBefore = v.substring(0,  cursorPos);
    var textAfter  = v.substring(cursorPos, v.length);

    $('#text').val(textBefore + $(this).val() + textAfter);
});

Solution 3 - Javascript

New answer:

https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/setRangeText

I'm not sure about the browser support for this though.

> Tested in Chrome 81.

function typeInTextarea(newText, el = document.activeElement) {
  const [start, end] = [el.selectionStart, el.selectionEnd];
  el.setRangeText(newText, start, end, 'select');
}

document.getElementById("input").onkeydown = e => {
  if (e.key === "Enter") typeInTextarea("lol");
}

<input id="input" />
<br/><br/>
<div>Press Enter to insert "lol" at caret.</div>
<div>It'll replace a selection with the given text.</div>

Old answer:

A pure JS modification of Erik Pukinskis' answer:

function typeInTextarea(newText, el = document.activeElement) {
  const start = el.selectionStart
  const end = el.selectionEnd
  const text = el.value
  const before = text.substring(0, start)
  const after  = text.substring(end, text.length)
  el.value = (before + newText + after)
  el.selectionStart = el.selectionEnd = start + newText.length
  el.focus()
}

document.getElementById("input").onkeydown = e => {
  if (e.key === "Enter") typeInTextarea("lol");
}

<input id="input" />
<br/><br/>
<div>Press Enter to insert "lol" at caret.</div>

> Tested in Chrome 47, 81, and Firefox 76.

If you want to change the value of the currently selected text while you're typing in the same field (for an autocomplete or similar effect), pass document.activeElement as the first parameter.

It's not the most elegant way to do this, but it's pretty simple.

Example usages:

typeInTextarea('hello');
typeInTextarea('haha', document.getElementById('some-id'));

Solution 4 - Javascript

For the sake of proper Javascript

HTMLTextAreaElement.prototype.insertAtCaret = function (text) {
  text = text || '';
  if (document.selection) {
    // IE
    this.focus();
    var sel = document.selection.createRange();
    sel.text = text;
  } else if (this.selectionStart || this.selectionStart === 0) {
    // Others
    var startPos = this.selectionStart;
    var endPos = this.selectionEnd;
    this.value = this.value.substring(0, startPos) +
      text +
      this.value.substring(endPos, this.value.length);
    this.selectionStart = startPos + text.length;
    this.selectionEnd = startPos + text.length;
  } else {
    this.value += text;
  }
};

Solution 5 - Javascript

A simple solution that works on firefox, chrome, opera, safari and edge but probably won't work on old IE browsers.

var target = document.getElementById("mytextarea_id")

if (target.setRangeText) {
	//if setRangeText function is supported by current browser
	target.setRangeText(data)
} else {
	target.focus()
	document.execCommand('insertText', false /*no UI*/, data);
}

setRangeText function allow you to replace current selection with the provided text or if no selection then insert the text at cursor position. It's only supported by firefox as far as I know.

For other browsers there is "insertText" command which only affect the html element currently focused and has same behavior as setRangeText

Inspired partially by this article

Solution 6 - Javascript

I like simple javascript, and I usually have jQuery around. Here's what I came up with, based off mparkuk's:

function typeInTextarea(el, newText) {
	var start = el.prop("selectionStart")
	var end = el.prop("selectionEnd")
	var text = el.val()
	var before = text.substring(0, start)
	var after  = text.substring(end, text.length)
	el.val(before + newText + after)
	el[0].selectionStart = el[0].selectionEnd = start + newText.length
	el.focus()
}

$("button").on("click", function() {
	typeInTextarea($("textarea"), "some text")
	return false
})

Here's a demo: http://codepen.io/erikpukinskis/pen/EjaaMY?editors=101

Solution 7 - Javascript

Rab's answer works great, but not for Microsoft Edge, so I added a small adaptation for Edge as well:

https://jsfiddle.net/et9borp4/

function insertAtCursor(myField, myValue) {
    //IE support
    if (document.selection) {
        myField.focus();
        sel = document.selection.createRange();
        sel.text = myValue;
    }
    // Microsoft Edge
    else if(window.navigator.userAgent.indexOf("Edge") > -1) {
      var startPos = myField.selectionStart; 
      var endPos = myField.selectionEnd; 
          
      myField.value = myField.value.substring(0, startPos)+ myValue 
             + myField.value.substring(endPos, myField.value.length); 
      
      var pos = startPos + myValue.length;
      myField.focus();
      myField.setSelectionRange(pos, pos);
    }
    //MOZILLA and others
    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);
    } else {
        myField.value += myValue;
    }
}

Solution 8 - Javascript

If the user does not touch the input after text is inserted, the 'input' event is never triggered, and the value attribute will not reflect the change. Therefore it is important to trigger the input event after programmatically inserting text. Focusing the field is not enough.

The following is a copy of Snorvarg's answer with an input trigger at the end:

function insertAtCursor(myField, myValue) {
    //IE support
    if (document.selection) {
        myField.focus();
        sel = document.selection.createRange();
        sel.text = myValue;
    }
    // Microsoft Edge
    else if(window.navigator.userAgent.indexOf("Edge") > -1) {
      var startPos = myField.selectionStart; 
      var endPos = myField.selectionEnd; 

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

      var pos = startPos + myValue.length;
      myField.focus();
      myField.setSelectionRange(pos, pos);
    }
    //MOZILLA and others
    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);
    } else {
        myField.value += myValue;
    }
    triggerEvent(myField,'input');
}

function triggerEvent(el, type){
  if ('createEvent' in document) {
    // modern browsers, IE9+
    var e = document.createEvent('HTMLEvents');
    e.initEvent(type, false, true);
    el.dispatchEvent(e);
  } else {
    // IE 8
    var e = document.createEventObject();
    e.eventType = type;
    el.fireEvent('on'+e.eventType, e);
  }
}

Credit to plainjs.com for the triggerEvent function

More about the oninput event at w3schools.com

I discovered this while creating an emoji-picker for a chat. If the user just select a few emojis and hit the "send" button, the input field is never touched by the user. When checking the value attribute it was always empty, even though the inserted emoji unicodes was visible in the input field. Turns out that if the user does not touch the field the 'input' event never fired and the solution was to trigger it like this. It took quite a while to figure this one out... hope it will save someone some time.

Solution 9 - Javascript

function insertAtCaret(text) {
  const textarea = document.querySelector('textarea')
  textarea.setRangeText(
    text,
    textarea.selectionStart,
    textarea.selectionEnd,
    'end'
  )
}

setInterval(() => insertAtCaret('Hello'), 3000)

<textarea cols="60">Stack Overflow Stack Exchange Starbucks Coffee</textarea>

Solution 10 - Javascript

The code below is a TypeScript adaptation of the package https://github.com/grassator/insert-text-at-cursor by Dmitriy Kubyshkin.


/**
 * Inserts the given text at the cursor. If the element contains a selection, the selection
 * will be replaced by the text.
 */
export function insertText(input: HTMLTextAreaElement | HTMLInputElement, text: string) {
  // Most of the used APIs only work with the field selected
  input.focus();

  // IE 8-10
  if ((document as any).selection) {
    const ieRange = (document as any).selection.createRange();
    ieRange.text = text;

    // Move cursor after the inserted text
    ieRange.collapse(false /* to the end */);
    ieRange.select();

    return;
  }

  // Webkit + Edge
  const isSuccess = document.execCommand("insertText", false, text);
  if (!isSuccess) {
    const start = input.selectionStart;
    const end = input.selectionEnd;
    // Firefox (non-standard method)
    if (typeof (input as any).setRangeText === "function") {
      (input as any).setRangeText(text);
    } else {
      if (canManipulateViaTextNodes(input)) {
        const textNode = document.createTextNode(text);
        let node = input.firstChild;

        // If textarea is empty, just insert the text
        if (!node) {
          input.appendChild(textNode);
        } else {
          // Otherwise we need to find a nodes for start and end
          let offset = 0;
          let startNode = null;
          let endNode = null;

          // To make a change we just need a Range, not a Selection
          const range = document.createRange();

          while (node && (startNode === null || endNode === null)) {
            const nodeLength = node.nodeValue.length;

            // if start of the selection falls into current node
            if (start >= offset && start <= offset + nodeLength) {
              range.setStart((startNode = node), start - offset);
            }

            // if end of the selection falls into current node
            if (end >= offset && end <= offset + nodeLength) {
              range.setEnd((endNode = node), end - offset);
            }

            offset += nodeLength;
            node = node.nextSibling;
          }

          // If there is some text selected, remove it as we should replace it
          if (start !== end) {
            range.deleteContents();
          }

          // Finally insert a new node. The browser will automatically
          // split start and end nodes into two if necessary
          range.insertNode(textNode);
        }
      } else {
        // For the text input the only way is to replace the whole value :(
        const value = input.value;
        input.value = value.slice(0, start) + text + value.slice(end);
      }
    }

    // Correct the cursor position to be at the end of the insertion
    input.setSelectionRange(start + text.length, start + text.length);

    // Notify any possible listeners of the change
    const e = document.createEvent("UIEvent");
    e.initEvent("input", true, false);
    input.dispatchEvent(e);
  }
}

function canManipulateViaTextNodes(input: HTMLTextAreaElement | HTMLInputElement) {
  if (input.nodeName !== "TEXTAREA") {
    return false;
  }
  let browserSupportsTextareaTextNodes;
  if (typeof browserSupportsTextareaTextNodes === "undefined") {
    const textarea = document.createElement("textarea");
    textarea.value = "1";
    browserSupportsTextareaTextNodes = !!textarea.firstChild;
  }
  return browserSupportsTextareaTextNodes;
}

Solution 11 - Javascript

Posting modified function for own reference. This example inserts a selected item from <select> object and puts the caret between the tags:

//Inserts a choicebox selected element into target by id
function insertTag(choicebox,id) {
    var ta=document.getElementById(id)
    ta.focus()
    var ss=ta.selectionStart
    var se=ta.selectionEnd
    ta.value=ta.value.substring(0,ss)+'<'+choicebox.value+'>'+'</'+choicebox.value+'>'+ta.value.substring(se,ta.value.length)
    ta.setSelectionRange(ss+choicebox.value.length+2,ss+choicebox.value.length+2)
}

Solution 12 - Javascript

/**
 * Usage "foo baz".insertInside(4, 0, "bar ") ==> "foo bar baz"
 */
String.prototype.insertInside = function(start, delCount, newSubStr) {
	return this.slice(0, start) + newSubStr + this.slice(start + Math.abs(delCount));
};

$('textarea').bind("keydown keypress", function (event) {
	var val = $(this).val();
	var indexOf = $(this).prop('selectionStart');
	if(event.which === 13) {
		val = val.insertInside(indexOf, 0,  "<br>\n");
		$(this).val(val);
		$(this).focus();
	}
});

Solution 13 - Javascript

Extending on Adriano's answer, we may also take cursor end into consideration which will make the "replace text" work

$('input[type=button]').on('click', function() {
    var cursorStart = $('#text').prop('selectionStart');
    var cursorEnd = $('#text').prop('selectionEnd');
    var v = $('#text').val();
    var textBefore = v.substring(0,cursorStart);
    var textAfter  = v.substring(cursorEnd);
    $('#text').val(textBefore + $(this).val() + textAfter);
});

Solution 14 - Javascript

Changed it to getElementById(myField):

function insertAtCursor(myField, myValue) {
	// IE support
	if (document.selection) {
		document.getElementById(myField).focus();
		sel = document.selection.createRange();
		sel.text = myValue;
	}
	// MOZILLA and others
	else if (document.getElementById(myField).selectionStart || document.getElementById(myField).selectionStart == '0') {
		var startPos = document.getElementById(myField).selectionStart;
		var endPos = document.getElementById(myField).selectionEnd;
		document.getElementById(myField).value =
				document.getElementById(myField).value.substring(0, startPos)
				+ myValue
				+ document.getElementById(myField).value.substring(endPos, document.getElementById(myField).value.length);
	} else {
		document.getElementById(myField).value += myValue;
	}
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJoshMWilliamsView Question on Stackoverflow
Solution 1 - JavascriptRaabView Answer on Stackoverflow
Solution 2 - JavascriptAdriano AlvesView Answer on Stackoverflow
Solution 3 - JavascriptJayant BhawalView Answer on Stackoverflow
Solution 4 - JavascriptEraView Answer on Stackoverflow
Solution 5 - JavascriptRamastView Answer on Stackoverflow
Solution 6 - JavascriptErik PukinskisView Answer on Stackoverflow
Solution 7 - JavascriptTornseglareView Answer on Stackoverflow
Solution 8 - JavascriptJetteView Answer on Stackoverflow
Solution 9 - Javascript井上智文View Answer on Stackoverflow
Solution 10 - JavascriptAndre PenaView Answer on Stackoverflow
Solution 11 - JavascriptAlexiyView Answer on Stackoverflow
Solution 12 - JavascriptzaarourView Answer on Stackoverflow
Solution 13 - JavascriptRohanView Answer on Stackoverflow
Solution 14 - JavascripttekagamiView Answer on Stackoverflow