Reputation: 20189
I have a contenteditable
element, and whenever I type some stuff and hit ENTER
it creates a new <div>
and places the new line text in there. I don't like this one little bit.
Is it possible to prevent this from happening or at least just replace it with a <br>
?
Here is demo http://jsfiddle.net/jDvau/
Note: This is not an issue in firefox.
Upvotes: 190
Views: 132366
Reputation: 476
There are different solutions on the internet and most of them handle keypress same way e.g execCommand
, charCode
, keyCode
, which
. Unfortunatelly these are deprecated and non-standard features use key
feature instead of these.
Also do not use contentEditable="plaintext-only"
try to handle enter
keypress and insert br
note to current selection.
Check my solution below it's working without any issue in Chrome, Firefox, Opera and Edge.
function handleEnterPress(e) {
if (e.key.toLowerCase() === 'enter') {
e.preventDefault();
let selection = window.getSelection();
let range = selection.getRangeAt(0);
range.insertNode(document.createElement('br'));
selection.collapseToEnd();
}
return false;
}
function handleEnterPress(e) {
if (e.key.toLowerCase() === 'enter') {
e.preventDefault();
let selection = window.getSelection();
let range = selection.getRangeAt(0);
range.insertNode(document.createElement('br'));
selection.collapseToEnd();
}
return false;
}
div[contenteditable="true"] {
background-color: bisque;
padding: 80px;
border: 1px solid black;
}
<div contenteditable="true" onkeypress="handleEnterPress(event)">Lorem ipsum dolor sit amet, consectetur adipisicing elit.</div>
Upvotes: 1
Reputation: 241
we can clean html at end like so
function cleanHtml(innerHTML: string) {
return innerHTML.replaceAll('<div><br></div>', '<br>')
}
in contentEditable do this
const { innerHTML, innerText } = contentEl
console.log({ innerHTML, innerText, cleanHtml: cleanHtml(innerHTML) })
Upvotes: 1
Reputation: 21915
The inserHTML
command solution does some weird things when you have nested contenteditable
elements.
I took some ideas from multiple answers here, and this seems to suit my needs for now:
element.addEventListener('keydown', function onKeyDown(e) {
// Only listen for plain returns, without any modifier keys
if (e.which != 13 || e.shiftKey || e.ctrlKey || e.altKey) {
return;
}
let doc_fragment = document.createDocumentFragment();
// Create a new break element
let new_ele = document.createElement('br');
doc_fragment.appendChild(new_ele);
// Get the current selection, and make sure the content is removed (if any)
let range = window.getSelection().getRangeAt(0);
range.deleteContents();
// See if the selection container has any next siblings
// If not: add another break, otherwise the cursor won't move
if (!hasNextSibling(range.endContainer)) {
let extra_break = document.createElement('br');
doc_fragment.appendChild(extra_break);
}
range.insertNode(doc_fragment);
//create a new range
range = document.createRange();
range.setStartAfter(new_ele);
range.collapse(true);
//make the caret there
let sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);
e.stopPropagation();
e.preventDefault();
return false;
});
// See if the given node has a next sibling.
// Either any element or a non-empty node
function hasNextSibling(node) {
if (node.nextElementSibling) {
return true;
}
while (node.nextSibling) {
node = node.nextSibling;
if (node.length > 0) {
return true;
}
}
return false;
}
Upvotes: 5
Reputation: 1913
I use hundreds of <td>
elements to input calculated values and found Firefox was adding a <div></div><br />
on enter which is not cool. So I used this onkeyup
:
$(document).on("keyup", '.first_td_col', function(e) {
if (e.key === 'Enter' || e.keyCode === 13) {
e.preventDefault();
$(this).empty();
return false;
}
// Do calculations if not enter
});
Of course this clears everything from the <td>
, even the users' input. But with a message displaying No enter please.
, it solves unnecessary elements getting in the way of just doing the calculation.
Upvotes: 1
Reputation:
This works in all major browsers (Chrome, Firefox, Safari, Edge)
document.addEventListener('keydown', event => {
if (event.key === 'Enter') {
document.execCommand('insertLineBreak')
event.preventDefault()
}
})
<div class="element" contenteditable="true">Sample text</div>
<p class="element" contenteditable="true">Sample text</p>
There is one inconvenience. After you finish editing, the elements might contain an ending <br>
inside. But you could add code to trim that down if you need to.
Check this answer to remove the trailing <br>
https://stackoverflow.com/a/61237737/670839
Upvotes: 50
Reputation: 4952
Try this:
$('div[contenteditable]').keydown(function(e) {
// trap the return key being pressed
if (e.keyCode === 13) {
// insert 2 br tags (if only one br tag is inserted the cursor won't go to the next line)
document.execCommand('insertHTML', false, '<br/>');
// prevent the default behaviour of return key pressed
return false;
}
});
Upvotes: 183
Reputation: 2888
On the W3C Editor's Draft there are some information about adding states into ContentEditable, and to prevent the browser for adding new element when pressing enter you can use plaintext-only
.
<div contentEditable="plaintext-only"></div>
Upvotes: 22
Reputation: 1148
I like to use Mousetrap for handlling hotkeys: https://craig.is/killing/mice
Then, I just intercept the enter event, executing a command insertLineBreak:
Mousetrap.bindGlobal('enter', (e)=>{
window.document.execCommand('insertLineBreak', false, null);
e.preventDefault();
});
All commands: https://developer.mozilla.org/en-US/docs/Web/API/Document/execCommand
It works using Chrome 75 and the following editable element:
<pre contenteditable="true"></pre>
It's also possible to use insertHTML:
window.document.execCommand('insertHTML', false, "\n");
Upvotes: 5
Reputation: 781
You can have separate <p>
tags for each line rather than using <br>
tags and gain greater browser compatibility out of the box.
To do this, put a <p>
tag with some default text inside of the contenteditable div.
For example, instead of:
<div contenteditable></div>
Use:
<div contenteditable>
<p>Replace this text with something awesome!</p>
</div>
Tested in Chrome, Firefox, and Edge, and the second works the same in each.
The first, however, creates divs in Chrome, creates line breaks in Firefox, and in Edge creates divs and the cursor is put back at the beginning of the current div instead of moving into the next one.
Tested in Chrome, Firefox, and Edge.
Upvotes: 6
Reputation: 17327
document.execCommand('defaultParagraphSeparator', false, 'p');
It overrides the default behavior to have paragraph instead.
On chrome the default behavior on enter is:
<div>
<br>
</div>
With that command it is gonna be
<p>
<br>
</p>
Now that it's more linear across it's easy to have only <br>
would you need to.
Upvotes: 26
Reputation: 9
Prevent New Div creation in content editable Div on each enter key: Solution That I have find is very simple:
var newdiv = document.createElement("div");
newdiv.innerHTML = "Your content of div goes here";
myEditablediv.appendChild(newdiv);
This --- innerHTML content prevent New Div creation in content editable Div on each enter key.
Upvotes: 0
Reputation: 314
It is possible to prevent this behaviour entirely.
$('<div class="temp-contenteditable-el" contenteditable="true"></div>').appendTo('body').focus().remove();
Upvotes: -1
Reputation: 673
You can do this with just a CSS change:
div{
background: skyblue;
padding:10px;
display: inline-block;
}
pre{
white-space: pre-wrap;
background: #EEE;
}
http://jsfiddle.net/ayiem999/HW43Q/
Upvotes: 55
Reputation: 899
Add style display:inline-block;
to contenteditable
, it will not generate div
, p
and span
automatically in Chrome.
Upvotes: 76
Reputation: 790
if (navigator.userAgent.toLowerCase().indexOf('msie') > -1) {
var range = document.getSelection();
range.pasteHTML(range.htmlText + '<br><br>');
}
else if(navigator.userAgent.toLocaleLowerCase().indexOf('trident') > -1) {
var range = document.getSelection().getRangeAt(0); //get caret
var nnode = document.createElement('br');
var bnode = document.createTextNode('\u00A0'); //
range.insertNode(nnode);
this.appendChild(bnode);
range.insertNode(nnode);
}
else
document.execCommand('insertHTML', false, '<br><br>')
Where this
is the actual context which means document.getElementById('test');
.
Upvotes: 1
Reputation: 1096
You can wrap your paragraphs with <p>
tag for example it would apper on new line instead of div
Example:
<div contenteditable="true"><p>Line</p></div>
After inserting new string:
<div contenteditable="true"><p>Line</p><p>New Line</p></div>
Upvotes: 3
Reputation: 95
Another way to do it
$('button').click(function(){
$('pre').text($('div')[0].outerHTML)
});
$("#content-edit").keydown(function(e) {
if(e.which == 13) {
$(this).find("div").prepend('<br />').contents().unwrap();
}
});
Upvotes: 0
Reputation: 4318
This is browser directed HTML5 editor. You can wrap your text with <p>...</p>
, then whenever you press ENTER you get <p></p>
. Also, the editor works this way that whenever you press SHIFT+ENTER it inserts <br />
.
<div contenteditable="true"><p>
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Dolor veniam asperiores laudantium repudiandae doloremque sed perferendis obcaecati delectus autem perspiciatis aut excepturi et nesciunt error ad incidunt impedit quia dolores rerum animi provident dolore corporis libero sunt enim. Ad magnam omnis quidem qui voluptas ut minima similique obcaecati doloremque atque!
<br /><br />
Type some stuff, hit ENTER a few times, then press the button.
</p>
</div>
Check this: http://jsfiddle.net/ZQztJ/
Upvotes: 2
Reputation: 5419
First we need to capture every key user enter to see if enter is pressed then we prevent the <div>
creation and we create our own <br>
tag.
There's one problem, when we create it our cursor stay at the same position so we use Selection API to place our cursor at the end.
Don't forget to add a <br>
tag at the end of your text because if you don't the first enter won't do a new line.
$('div[contenteditable]').on('keydown', function(e) {
var key = e.keyCode,
el = $(this)[0];
// If Enter
if (key === 13) {
e.preventDefault(); // Prevent the <div /> creation.
$(this).append('<br>'); // Add the <br at the end
// Place selection at the end
// http://stackoverflow.com/questions/4233265/contenteditable-set-caret-at-the-end-of-the-text-cross-browser
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();
}
}
});
Upvotes: 2
Reputation: 2259
I'd use styling (Css) to fix the issue.
div[contenteditable=true] > div {
padding: 0;
}
Firefox indeed adds a the block element break
, whereas Chrome wraps each section in a tag. You css gives divs a padding of 10px along with the background color.
div{
background: skyblue;
padding:10px;
}
Alternatively, you can replicate the same desired effect in jQuery:
var style = $('<style>p[contenteditable=true] > div { padding: 0;}</style>');
$('html > head').append(style);
Here's a fork of your fiddle http://jsfiddle.net/R4Jdz/7/
Upvotes: 4
Reputation: 92
The way that contenteditable
behaves when you press enter depends on browsers, the <div>
happens on webkit (chrome, safari) and IE.
I struggled with this few month ago and I corrected it this way :
//I recommand you trigger this in case of focus on your contenteditable
if( navigator.userAgent.indexOf("msie") > 0 || navigator.userAgent.indexOf("webkit") > 0 ) {
//Add <br> to the end of the field for chrome and safari to allow further insertion
if(navigator.userAgent.indexOf("webkit") > 0)
{
if ( !this.lastChild || this.lastChild.nodeName.toLowerCase() != "br" ) {
$(this).html( $(this).html()+'<br />' );
}
}
$(this).keypress( function(e) {
if( ( e.keyCode || e.witch ) == 13 ) {
e.preventDefault();
if( navigator.userAgent.indexOf("msie") > 0 ) {
insertHtml('<br />');
}
else {
var selection = window.getSelection(),
range = selection.getRangeAt(0),
br = document.createElement('br');
range.deleteContents();
range.insertNode(br);
range.setStartAfter(br);
range.setEndAfter(br);
range.collapse(false);
selection.removeAllRanges();
selection.addRange(range);
}
}
});
}
I hope it will help, and sorry for my english if it's not as clear as needed.
EDIT : Correction of removed jQuery function jQuery.browser
Upvotes: 6
Reputation: 7199
Use shift+enter instead of enter to just put a single <br>
tag in or wrap your text in <p>
tags.
Upvotes: 13
Reputation: 276
Try using ckeditor. It also provide formatting like this one in SOF.
https://github.com/galetahub/ckeditor
Upvotes: 2
Reputation: 4167
add a prevent default to the div
document.body.div.onkeydown = function(e) {
if ( e.keycode == 13 ){
e.preventDefault();
//add a <br>
div = document.getElementById("myDiv");
div.innerHTML += "<br>";
}
}
Upvotes: 2
Reputation: 5340
Try this:
$('div[contenteditable="true"]').keypress(function(event) {
if (event.which != 13)
return true;
var docFragment = document.createDocumentFragment();
//add a new line
var newEle = document.createTextNode('\n');
docFragment.appendChild(newEle);
//add the br, or p, or something else
newEle = document.createElement('br');
docFragment.appendChild(newEle);
//make the br replace selection
var range = window.getSelection().getRangeAt(0);
range.deleteContents();
range.insertNode(docFragment);
//create a new range
range = document.createRange();
range.setStartAfter(newEle);
range.collapse(true);
//make the cursor there
var sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);
return false;
});
http://jsfiddle.net/rooseve/jDvau/3/
Upvotes: 25