When you hit Enter on a contentEditable
element every browser is handling the resulting code differently: Firefox inserts a BR tag, Chrome inserts a DIV tag while Internet Explorer inserts a P tag.
I was desperately looking for a solution to at least use a BR or P for all browsers and the most mon answer was this:
inserting BR tag :
$("#editableElement").on("keypress", function(e){
if (e.which == 13) {
if (window.getSelection) {
var selection = window.getSelection(),
range = selection.getRangeAt(0),
br = document.createElement("br");
range.deleteContents();
range.insertNode(br);
range.setStartAfter(br);
range.setEndAfter(br);
selection.removeAllRanges();
selection.addRange(range);
return false;
}
}
});
But this doesn't work because it seems that browsers don't know how to set the caret after <br>
which means the following is not doing anything useful (especially if you hit enter when the caret is placed at the end of text):
range.setStartAfter(br);
range.setEndAfter(br);
Some people would say: use double <br><br>
but this results in two line breaks when you hit enter inside a text node.
Others would say always add an additional <br>
at the end of contentEditable, but if you have a <div contenteditable><p>text here</p></div>
and you place the cursor at the end of text then hit enter, you will get the wrong behavior.
So I said to myself maybe we can use P instead of BR, and the mon answer is:
inserting P tag:
document.execCommand('formatBlock', false, 'p');
But this doesn't work consistently either.
As you can see, all these solutions leave something to be desired. Is there another solution that solves this issue?
When you hit Enter on a contentEditable
element every browser is handling the resulting code differently: Firefox inserts a BR tag, Chrome inserts a DIV tag while Internet Explorer inserts a P tag.
I was desperately looking for a solution to at least use a BR or P for all browsers and the most mon answer was this:
inserting BR tag :
$("#editableElement").on("keypress", function(e){
if (e.which == 13) {
if (window.getSelection) {
var selection = window.getSelection(),
range = selection.getRangeAt(0),
br = document.createElement("br");
range.deleteContents();
range.insertNode(br);
range.setStartAfter(br);
range.setEndAfter(br);
selection.removeAllRanges();
selection.addRange(range);
return false;
}
}
});
But this doesn't work because it seems that browsers don't know how to set the caret after <br>
which means the following is not doing anything useful (especially if you hit enter when the caret is placed at the end of text):
range.setStartAfter(br);
range.setEndAfter(br);
Some people would say: use double <br><br>
but this results in two line breaks when you hit enter inside a text node.
Others would say always add an additional <br>
at the end of contentEditable, but if you have a <div contenteditable><p>text here</p></div>
and you place the cursor at the end of text then hit enter, you will get the wrong behavior.
So I said to myself maybe we can use P instead of BR, and the mon answer is:
inserting P tag:
document.execCommand('formatBlock', false, 'p');
But this doesn't work consistently either.
As you can see, all these solutions leave something to be desired. Is there another solution that solves this issue?
Share Improve this question edited Mar 2, 2016 at 22:17 Peter O. 32.9k14 gold badges84 silver badges97 bronze badges asked Feb 29, 2016 at 17:05 medBouzidmedBouzid 8,41211 gold badges60 silver badges93 bronze badges 1- 1 I feel you... I'm facing the same annoying problem :) – Swag Commented Mar 2, 2016 at 20:59
2 Answers
Reset to default 11 +250One possible solution: append a text node with a zero-width space character after the <br>
element. This is a non-printing zero-width character that's specifically designed to:
...indicate word boundaries to text processing systems when using scripts that do not use explicit spacing, or after characters (such as the slash) that are not followed by a visible space but after which there may nevertheless be a line break.
(Wikipedia)
Tested in Chrome 48, Firefox 43, and IE11.
$("#editableElement").on("keypress", function(e) {
//if the last character is a zero-width space, remove it
var contentEditableHTML = $("#editableElement").html();
var lastCharCode = contentEditableHTML.charCodeAt(contentEditableHTML.length - 1);
if (lastCharCode == 8203) {
$("#editableElement").html(contentEditableHTML.slice(0, -1));
}
// handle "Enter" keypress
if (e.which == 13) {
if (window.getSelection) {
var selection = window.getSelection();
var range = selection.getRangeAt(0);
var br = document.createElement("br");
var zwsp = document.createTextNode("\u200B");
var textNodeParent = document.getSelection().anchorNode.parentNode;
var inSpan = textNodeParent.nodeName == "SPAN";
var span = document.createElement("span");
// if the carat is inside a <span>, move it out of the <span> tag
if (inSpan) {
range.setStartAfter(textNodeParent);
range.setEndAfter(textNodeParent);
}
// insert the <br>
range.deleteContents();
range.insertNode(br);
range.setStartAfter(br);
range.setEndAfter(br);
// create a new span on the next line
if (inSpan) {
range.insertNode(span);
range.setStart(span, 0);
range.setEnd(span, 0);
}
// add a zero-width character
range.insertNode(zwsp);
range.setStartBefore(zwsp);
range.setEndBefore(zwsp);
// insert the new range
selection.removeAllRanges();
selection.addRange(range);
return false;
}
}
});
#editableElement {
height: 150px;
width: 500px;
border: 1px solid black;
}
<script src="https://ajax.googleapis./ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div contenteditable=true id="editableElement">
<span>sample text</span>
</div>
You can see a full cross browser implementation here. There are so many hacks to make it work. This code from the link would help you to device a solution.
Example of a Geko and IE hack:
doc.createElement( 'br' ).insertAfter( startBlock );
// A text node is required by Gecko only to make the cursor blink.
if ( CKEDITOR.env.gecko )
doc.createText( '' ).insertAfter( startBlock );
// IE has different behaviors regarding position.
range.setStartAt( startBlock.getNext(),
CKEDITOR.env.ie ? CKEDITOR.POSITION_BEFORE_START :
CKEDITOR.POSITION_AFTER_START );