I am working on creating my own chat application in which I used content-editable div
as chatbox.
I am implementing mention feature where my mention is username wrapped in a span tag followed by a space(
) but my problem is when I remove space my cursor moves to the end of the div.
with space
<html>
<head>
</head>
<body>
<div contenteditable=true><span contenteditable='false'>UserName</span> </div>
</body>
</html>
without space
<html>
<head>
</head>
<body>
<div contenteditable=true><span contenteditable='false'>UserName</span></div>
</body>
</html>
This is how I implemented in code and also this bug happens only in chrome.
The problem is that your contenteditable element is a div , which by default is display: block . This is what causes your caret position problem. This can be fixed by making the outermost div non-editable and adding a new editable div that will be treated as inline-block .
moveToElementText(contentEditableElement);//Select the entire contents of the element with the range range. collapse(false);//collapse the range to the end point. false means collapse to end rather than the start range. select();//Select the range (make it the visible selection } } }( window.
In order to set caret cursor position in content editable elements like div tag is carried over by JavaScript Range interface. The range is created using document. createRange() method.
contentEditable prop in ReactWhen you add contentEditable=true to a component you see a warning from React: Warning: A component is `contentEditable` and contains `children` managed by React. It is now your responsibility to guarantee that none of those nodes are unexpectedly modified or duplicated.
This is actually a bug in the browsers, I have a workaround but I don't know how much it will help you but this is the best we can do now in my knowledge.
div>span {
display:inline-block;
}
<div contenteditable="true"><span contenteditable="true"><span contenteditable="false">UserName</span></span> </div>
Without space
div>span {
display:inline-block;
}
<div contenteditable="true"><span contenteditable="true"><span contenteditable="false">UserName</span></span></div>
If you want a full proof content to be there then here is a solution with script
combining : before
pseudo:
Here am taking the width of the : before
pseudo-element and hading it over to the div
element padding-left
. I have used script keeping in mind of your dynamic usernames.
var testBox = document.querySelector('.test'),
pseudoBeforeWidth = window.getComputedStyle(testBox, ':before').width, //getting the width of the parent elemnts `:before`
pseudoBeforeContent = window.getComputedStyle(testBox, ':before').content;
testBox.style.paddingLeft = pseudoBeforeWidth; //handing the width to the parent elemnts padding left style
var i = 0
var n = 0;
testBox.addEventListener('keydown', function(event) {
const key = event.key; // const {key} = event; ES6+
if ((key === "Backspace" || key === "Delete") && n == 0) {
i++
console.log(testBox.textContent, i, n);
if (testBox.textContent == "" && i >= 2) {
testBox.className += ' userhide ';
testBox.style.paddingLeft = 0;
n = 1;
}
}
});
div:before {
content: attr(data-user);
display: inline-block;
position: absolute;
left: 5px;
}
.test.userhide:before {
display: none;
}
<div class="test" contenteditable="true" data-user="UserName"></div>
I hope this was helpful for you.
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:
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
.
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
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.
This Can Help You
<div contenteditable=true style="display: inline-block;background: #000;color:#fff;"><span contenteditable=false>UserName</span> </div>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With