How to set the caret (cursor) position in a contenteditable element (div)?
In most browsers, you need the Range
and Selection
objects. You specify each of the selection boundaries as a node and an offset within that node. For example, to set the caret to the fifth character of the second line of text, you'd do the following:
function setCaret() {
var el = document.getElementById("editable")
var range = document.createRange()
var sel = window.getSelection()
range.setStart(el.childNodes[2], 5)
range.collapse(true)
sel.removeAllRanges()
sel.addRange(range)
}
<div id="editable" contenteditable="true">
text text text<br>text text text<br>text text text<br>
</div>
<button id="button" onclick="setCaret()">focus</button>
Set caret position in a content editable element
Try this:
Just replace range.setStart(el, 2) with range.setStart(el.childNodes[0], 2)
var el = document.getElementsByTagName('div')[0];var range = document.createRange();var sel = window.getSelection();range.setStart(el.childNodes[0], 2);range.collapse(true);sel.removeAllRanges();sel.addRange(range);el.focus();
<div contenteditable>Hi ! How are you doing ?</div>
Set Caret Position in 'contenteditable' div that has children
So, I was experiencing the same issue and decided to write my own routine quickly, it walks through all the child nodes recursively and set the position.
Note how this takes a DOM node as argument, not a jquery object as your original post does
// Move caret to a specific point in a DOM element
function SetCaretPosition(el, pos){
// Loop through all child nodes
for(var node of el.childNodes){
if(node.nodeType == 3){ // we have a text node
if(node.length >= pos){
// finally add our range
var range = document.createRange(),
sel = window.getSelection();
range.setStart(node,pos);
range.collapse(true);
sel.removeAllRanges();
sel.addRange(range);
return -1; // we are done
}else{
pos -= node.length;
}
}else{
pos = SetCaretPosition(node,pos);
if(pos == -1){
return -1; // no need to finish the for loop
}
}
}
return pos; // needed because of recursion stuff
}
I hope this'll help you!
Set the selector cursor to a new position in contenteditable div
<div>
elements have no value
property
$("#buttonbold").click(function(){
content.focus();
var valuelength = content.textContent.length - 4;
content.setSelectionRange(content.textContent.length,valuelength);
});
.
<div>
elements do not have a setSelectionRange
method either,
so here is a solution to make this kind of selection for elements using the contenteditable
property:
const myDiv = document.getElementById('my-div') , btSelectRange = document.getElementById('bt-select-range') ;function setSelectionRangeCE(el, pos, len) { el.focus(); let range = document.createRange() , sel = window.getSelection() ; range.setStart(el.firstChild, pos) range.setEnd(el.firstChild, pos+len) sel.removeAllRanges() sel.addRange(range) }btSelectRange.onclick=_=> { setSelectionRangeCE(myDiv,2,5) }
#my-div { margin: 1em; padding: .7em; width: 16em; height: 3em; border: 1px solid grey; }button { margin: 1em; }
<div id="my-div" contenteditable >hello world</div>
<button id="bt-select-range" > select range pos:2 len:5 </button>
Get and set cursor position with contenteditable div
A good rich-text editor is one of the harder things to do currently, and is pretty much a project by itself (unfriendly API, huge number of corner cases, cross-browser differences, the list goes on). I would strongly advise you to try and find an existing solution.
Some libraries that can be used include:
- Quill (http://quilljs.com)
- WYSGIHTML (http://wysihtml.com)
- CodeMirror library (http://codemirror.net)
How to add cursor position after adding a component to content-editable div
So, the problem was I have applied a "display:flex" property to the parent div and now display: "inline-block" helped and its done. Now just applying focus to the main div, I get the the cursor position after the component added.
Set cursor position in content-editable div
Here's a much simpler approach. There are a few things to note:
keypress
is the only key event in which you can reliably detect which character has been typed.keyup
andkeydown
won't do.- The code handles the insertion of parentheses/braces manually by preventing the default action of the
keypress
event. - The selection/caret stuff is simple when using DOM methods.
- This won't work in IE <= 8, which have different range and selection APIs. If you need support for those browsers, I'd suggest using my own Rangy library. It is possible without it but I really don't want to write the extra code.
Demo:
http://jsfiddle.net/HPeb2/
Code:
var editableEl = document.getElementById("editable");
editableEl.addEventListener("keypress", function(e) {
var charTyped = String.fromCharCode(e.which);
if (charTyped == "{" || charTyped == "(") {
// Handle this case ourselves
e.preventDefault();
var sel = window.getSelection();
if (sel.rangeCount > 0) {
// First, delete the existing selection
var range = sel.getRangeAt(0);
range.deleteContents();
// Insert a text node at the caret containing the braces/parens
var text = (charTyped == "{") ? "{}" : "()";
var textNode = document.createTextNode(text);
range.insertNode(textNode);
// Move the selection to the middle of the inserted text node
range.setStart(textNode, 1);
range.setEnd(textNode, 1);
sel.removeAllRanges();
sel.addRange(range);
}
}
}, false);
Cursor moves to end of the contenteditable div when character removed from div
Analysis
Think of a simple text editor(notepad) where you have typed three characters - TRY
Now, its obvious that the cursor can be placed only at 4 places here, which are:
- before T
- between T and R
- between R and Y
- after Y
The reason for which is simply because, these 3 characters are the only editable ones here and they are 3 individual entities, which can't be edited/separated further. For example, we can't place the cursor in between the letter 'T' and separate the ┐
and ┌
from it.
Same is the case with your scenario as the cursor is moved to the end of the div once the
is cleared because the contenteditable=true
is set to the <div>
and is set as false
to the <span>
. Therefore the div
is the only editable element here and the span
is not. So the cursor can position itself only on an editable place which is either at the beginning of an editable element(div
in this case) or at the end of it and not in between.
As the div
is a block element, the cursor is moved to the end of the page as the block elements occupy the whole width of its parent. We can see the cursor being moved to the middle of the page if we set width: 50%;
to the div
.
Solution
Considering your comments on other answers, that you need to keep the width as 100%
, the solution is to wrap the div
with another one which also have the attribute contenteditable=true
and keep the child div
as an inline-block
element.
<div contenteditable=true>
<div class="inl-blck" contenteditable=true><span contenteditable='false'>UserName</span> </div>
</div>
CODEPEN
Explanation
Here, both the parent and child div
s are editable where the parent occupying the full width (100%) and the child is an inline-block
element, which just occupies the space of its contents. Therefore, once the
is cleared, the cursor moves to the end of the next editable content which is the child div
.
Note that, you need to keep the child div
and span
along with the
in the same line in you code as otherwise it will create extra characters (whitespaces) in the section, which will break the contenteditable
further.
Hope this helps.
Related Topics
Pass JavaScript Variable to PHP Via Ajax
Html Text Input Allow Only Numeric Input
How to Programmatically Tell an HTML Select to Drop Down (For Example, Due to Mouseover)
Converting HTML String into Dom Elements
How to Get Js Variable to Retain Value After Page Refresh
Using HTML Script Tags to Code While They Have a Source
Navbar Dropdown (Collapse) Is Not Working in Bootstrap 5
How to Calculate the Number of Days Between Two Dates
Cross-Browser Multi-Line Text Overflow With Ellipsis Appended Within a Fixed Width and Height
Unescape HTML Entities in JavaScript
How to Create a ≪Style≫ Tag With JavaScript
How to Check File Mime Type With JavaScript Before Upload
How to Dynamically Change a Web Page'S Title
Vue.Js Dynamic Images Not Working
How Does the Paste Image from Clipboard Functionality Work in Gmail and Google Chrome 12+