contenteditable, set caret at the end of the text (cross-browser)
The following function will do it in all major browsers:
function placeCaretAtEnd(el) { el.focus(); if (typeof window.getSelection != "undefined" && typeof document.createRange != "undefined") { var range = document.createRange(); range.selectNodeContents(el); range.collapse(false); var sel = window.getSelection(); sel.removeAllRanges(); sel.addRange(range); } else if (typeof document.body.createTextRange != "undefined") { var textRange = document.body.createTextRange(); textRange.moveToElementText(el); textRange.collapse(false); textRange.select(); }}placeCaretAtEnd( document.querySelector('p') );
p{ padding:.5em; border:1px solid black; }
<p contentEditable>foo bar </p>
Placing the caret at the start is almost identical: it just requires changing the Boolean passed into the calls to collapse()
. Here's an example that creates functions for placing the caret at the start and at the end:
function createCaretPlacer(atStart) { return function(el) { el.focus(); if (typeof window.getSelection != "undefined" && typeof document.createRange != "undefined") { var range = document.createRange(); range.selectNodeContents(el); range.collapse(atStart); var sel = window.getSelection(); sel.removeAllRanges(); sel.addRange(range); } else if (typeof document.body.createTextRange != "undefined") { var textRange = document.body.createTextRange(); textRange.moveToElementText(el); textRange.collapse(atStart); textRange.select(); } };}var placeCaretAtStart = createCaretPlacer(true);var placeCaretAtEnd = createCaretPlacer(false);
Unfortunately Tim's excellent answer worked for me only for placing at the end, for placing at the start I had to modify it slightly.
function setCaret(target, isStart) { const range = document.createRange(); const sel = window.getSelection(); if (isStart){ const newText = document.createTextNode(''); target.appendChild(newText); range.setStart(target.childNodes[0], 0); } else { range.selectNodeContents(target); } range.collapse(isStart); sel.removeAllRanges(); sel.addRange(range); target.focus(); target.select();}
Not sure though if focus()
and select()
are actually needed.
This (live) example shows a short simple function, setCaretAtStartEnd
, which takes two arguments; A (editable) node to place the caret at & a Boolean indicating where to place it (start or end of the node)
const editableElm = document.querySelector('[contenteditable]');document.querySelectorAll('button').forEach((elm, idx) => elm.addEventListener('click', () => { editableElm.focus() setCaretAtStartEnd(editableElm, idx) }))function setCaretAtStartEnd( node, atEnd ){ const sel = document.getSelection(); node = node.firstChild; if( sel.rangeCount ){ ['Start', 'End'].forEach(pos => sel.getRangeAt(0)["set" + pos](node, atEnd ? node.length : 0) ) }}
[contenteditable]{ padding:5px; border:1px solid; }
<h1 contenteditable>Place the caret anywhere</h1><br><button>Move caret to start</button><button>Move caret to end</button>