145

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.

iConnor
  • 19,153
  • 13
  • 57
  • 91
  • 1
    firefox adds
    , chrome - not, but after fixing your styles, extra divs do not break left padding. Question is why you dont like it? Think it is br... http://jsfiddle.net/jDvau/1/ Also you can use DOMSubtreeModified event on catch these divs and remove them.
    – ViliusL Dec 05 '13 at 10:46
  • http://stackoverflow.com/questions/6024594/avoid-createelement-function-if-its-inside-a-li-element-contenteditable this could help you, good luck! – Sirikon Dec 05 '13 at 10:58
  • have also a look here http://stackoverflow.com/questions/3080529/make-a-br-instead-of-div-div-by-pressing-enter-on-a-contenteditable – BeNdErR Dec 05 '13 at 11:00
  • Possible duplicate of: http://stackoverflow.com/questions/3080529/make-a-br-instead-of-div-div-by-pressing-enter-on-a-contenteditable – backdesk Dec 10 '13 at 15:25
  • 1
    To me Blake Plumb's solution is the simplest and from far the best down here. – svassr Dec 11 '13 at 04:49
  • Similar Question: http://stackoverflow.com/questions/6023307/dealing-with-line-breaks-on-contenteditable-div – sv_in Dec 11 '13 at 06:44
  • 1
    @svassr that's not the point, it's not you or I that will be using it, It's a client that may not even know what shift is. – iConnor Dec 11 '13 at 08:06
  • 2
    Indeed it changes everything. That said it's a common behaviour and small help message would'nt arm. "Give a man a fish and you feed him for a day. Teach a man to fish and you feed him for a lifetime." – svassr Dec 11 '13 at 18:36
  • need add ```e.preventDefault()``` before ```return false``` – L.T Nov 05 '15 at 17:15

23 Answers23

167

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;
    }
});

Click here for demo

shiva
  • 3,483
  • 5
  • 16
  • 37
Ram G Athreya
  • 4,604
  • 6
  • 23
  • 57
  • 1
    But I find a little difference here. Put your cursor just on the blank line(on the top of "Type some stuff"), and press enter. The cursor is now just before the "Type", not on the new blank line. – Andrew Dec 06 '13 at 11:23
  • @Andrew yes that is correct, It would be good if you can fix this Ram – iConnor Dec 06 '13 at 16:33
  • I am sorry I can't find an easy fix for this at the moment & I am a little busy with work & all, I will try my best to find a workaround for this issue soon – Ram G Athreya Dec 11 '13 at 12:29
  • 3
    This doesn't work in IE11 as it does not support insertHTML. See answer below! – webprogrammer Apr 01 '14 at 17:10
  • In chrome if you try this within a blockquote, it automatically creates a new blockquote as well, not the desired behavior. – daedelus_j May 21 '14 at 18:48
  • 4
    If you put your cursor between characters eg. 'Ty[cursor]pe some stuff' and hit enter, you get 1 line too many. – Chandrew May 27 '14 at 22:32
  • 14
    Answer is not acceptable. Solution would be to have only one
    – raoulinski Dec 12 '14 at 20:55
  • 3
    this return both
    and
    – Nishad Up Sep 10 '15 at 10:53
  • if there is multiple contentEditable then it will insert extra br. If there is four contentEditable then four break will occur – HADI Nov 29 '15 at 10:35
  • answers half the question without trying to answer the first part, which is to prevent this from happening – vsync Oct 14 '16 at 23:00
  • another prob here is that it takes no account of modifiers... when using `keydown` you want to do sthg like `if ... && ! e.ctrlKey && ! e.shiftKey && ! e.altKey` as appropriate... – mike rodent Sep 24 '17 at 13:33
  • The `insertHTML` command will indeed produce some weird results when you have nested `contenteditable` elements. Andrew's answer, where you replace the current selection with a new document fragment, is better for this. – skerit Jul 31 '18 at 11:21
  • I want to do this whiling pasting text, is it possible? – Sushil Jan 31 '20 at 09:32
  • I find it will not insert `
    ` when the cursor is before a `
    `. Chrome 80. Weird.
    – Jack Lu Mar 13 '20 at 07:56
  • I have added a modern solution (check below), which actually works as expected. –  Apr 15 '20 at 19:52
  • A solution with pure javascript is preferred. – Dror Bar Apr 20 '20 at 18:02
  • `.execCommand()` is now considered obsolete by MDN... See [Document.execCommand()](https://developer.mozilla.org/en-US/docs/Web/API/Document/execCommand) – SO Stinks Apr 28 '20 at 09:13
52

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/

Michael Mrozek
  • 149,906
  • 24
  • 156
  • 163
airi
  • 635
  • 5
  • 11
  • 1
    There was a problem when I used inline-block, execute execCommand("insertHTML", xxx) to insert anything, a "
    " will added at the end of inserted element, tested in Chrome33.
    – Imskull May 15 '14 at 06:42
  • 5
    Nice find. Sadly this won't work on position: absolute elements or elements that are direct children of a parent with display: flex. You can hack it to work though keeping that in mind. Just make sure it's not a direct child of flex elements. If you need it position: absolute just give it a extra parent with that. – Sceptic Mar 03 '16 at 09:00
  • @ReinoutvanKempen Started using flex 3 months ago already. I guess this hack won't work – kittu Aug 23 '17 at 12:37
  • this is a really really greatest solution, it is extreme clean and clear, nothing will be insert, even include br. and especially this solution without js. – defend orca Mar 08 '19 at 02:30
  • 2
    Wow... this solves Chrome, but makes Firefox begin adding divs on enter, which it doesn't by default. – cbdeveloper Apr 24 '19 at 15:00
  • This also doesn't work when the element is a grid child. The inline-block will not do anything, and pressing Enter still inserts
    s.
    –  Apr 15 '20 at 19:21
51

Add style display:inline-block; to contenteditable, it will not generate div, p and span automatically in Chrome.

Arman H
  • 5,018
  • 9
  • 47
  • 70
Le Tung Anh
  • 599
  • 4
  • 7
  • 10
    This is a great solution. `*[contenteditable="true"]{display: inline-block;}` – ericjbasti Jun 02 '15 at 14:13
  • Love it, simple but effective – user25794 Dec 15 '15 at 03:19
  • In IE11 this will make an extra ``

    `` :(
    – Betty St May 03 '16 at 11:52
  • 1
    **but** it will create another very annoying [Chrome bug](http://stackoverflow.com/q/34354085/104380) (what a shitty browser) – vsync Oct 14 '16 at 23:03
  • This solved a line break problem I was trying to fix for the last six months! Thank you @le-tung-anh – Jay Jee Jul 13 '17 at 01:12
  • ericjbasti's CSS snippet *is not a great solution* performance-wise. Wildcard selectors are costly. Make sure to specify it for elements that actually will use it. – zamber Aug 10 '17 at 12:47
  • 8
    Does not work anymore with Chrome Version 63.0.3239.84 – Mikaël Mayer Dec 27 '17 at 20:41
  • With the answer of @airi, I discovered that the contenteditable should be a
    . It cannot be a or a for this idea to work
    – Mikaël Mayer Dec 27 '17 at 21:00
  • Glad this works, but it's dumb that this works. The difference between `inline-block` and `block` is supposed to be in the flow [**outside the element**](https://stackoverflow.com/a/14033814/673991). This solution reveals a distinction Chrome makes inside the element. Chrome should behave the same for `display:block`. – Bob Stein Aug 06 '19 at 16:59
  • This doesn't work when the element is a grid child. The inline-block will not do anything, and pressing Enter still inserts
    s.
    –  Apr 15 '20 at 19:22
  • This works for my case. – Kopi Bryant Apr 04 '21 at 08:02
  • great! simple enough, now it inserts
    instead of
    – datdinhquoc Apr 11 '21 at 10:16
23

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/

Andrew
  • 5,128
  • 1
  • 14
  • 21
  • Good, works :) I'll await more attention before I decide, thanks. – iConnor Dec 05 '13 at 11:12
  • doesn't work properly on firefox. it adds one extra line. – agpt Jul 01 '16 at 12:51
  • This makes it so that the `input` doesn't get triggered when you press enter. A simple solution: add sth like `$(this).trigger('input')` – LarsW Aug 15 '16 at 13:52
  • The `insertHTML` solution does some weird things when there are nested `contenteditable` elements, your solution circumvents that but there are some more issues, I added it as a new possible solution. – skerit Jul 31 '18 at 11:56
  • Doesn't work on Chrome. First time when you press enter at the end of the string, it adds a space. The second time it works though. –  Apr 15 '20 at 19:24
22
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.

Ced
  • 12,657
  • 11
  • 62
  • 124
  • When you press enter, instead of having div and br you'll have p and br accross browser. Try it. – Ced Feb 25 '16 at 21:16
  • Thanks! Explanations are always helpful – jpaugh Feb 25 '16 at 22:01
  • @jpaugh np, I edited my answer further so it explains better. – Ced Feb 25 '16 at 22:06
  • this doesn't work on firefox (I tested in chrome and firefox only) – medBouzid Feb 29 '16 at 13:00
  • FireFox has been fixed to now respect the defaultParagraphSeparator. IMHO this make this answer the best as it make all browsers now consistent and inline with the spec. If you then don't want a P tag to have a margin 'spacing' from the previous text block in content editable then you can use css to modify that. – blackmamba May 08 '18 at 14:58
  • I does execute twice for the first time. – Ahtisham Nov 02 '18 at 06:49
  • This was the best fix after hours of search. IE11 and modern browsers work with this solution. – JoJo Jun 07 '19 at 14:31
  • This is nice but I really wish you could change it to just `br` and not have the extra `p` tag at all. – Max Oct 30 '19 at 17:26
18

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

  • 3
    What the heck? How can the only solution that actually worked for me be this far down the page? Thanks so much. – user12861 Jul 27 '20 at 03:11
  • You just made my day, this took hours to figure out - thanks! – Alexander Kludt Sep 09 '20 at 14:47
  • execCommand is depricated! This feature is no longer recommended. Though some browsers might still support it, it may have already been removed from the relevant web standards. – ahsan ayub Feb 09 '21 at 10:22
11

Use shift+enter instead of enter to just put a single <br> tag in or wrap your text in <p> tags.

Blake Plumb
  • 5,667
  • 2
  • 28
  • 49
5

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

Elie
  • 82
  • 2
  • 3
  • Just to let you know, `jQuery.browser` is no longer part of jQuery. – iConnor Dec 06 '13 at 16:32
  • You've right, I should mention this and use something like `navigator.userAgent.indexOf("msie") > 0` and `navigator.userAgent.indexOf("webkit") > 0` – Elie Dec 06 '13 at 16:48
  • 1
    `if( ( e.keyCode || e.witch ) == 13 ) { ... }` needs to be `if (e.keyCode === 13 || e.which === 13) { ... }` – Sebastian Sandqvist Apr 04 '16 at 06:19
5

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>

jsfiddle

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.

Josh Powlison
  • 553
  • 7
  • 11
5

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");
Gauss
  • 918
  • 13
  • 13
4

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>";
    }
}
Math chiller
  • 3,931
  • 5
  • 23
  • 40
  • @connorspiracist sorry its `document.body.div` (you probably will need to put in some other code to point to correct `div` its just the general idea) – Math chiller Dec 05 '13 at 11:11
4

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/

cbayram
  • 2,169
  • 9
  • 9
  • 1
    This may help some people but I was more concerned about the unessasary markup, as I would be taking the final HTML of the `contenteditable` and using it elsewhere – iConnor Dec 12 '13 at 20:34
3

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>

nes
  • 856
  • 6
  • 10
3

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 cursor 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;
}
skerit
  • 17,691
  • 22
  • 92
  • 138
2

Try using ckeditor. It also provide formatting like this one in SOF.

https://github.com/galetahub/ckeditor

Dan Rey Oquindo
  • 244
  • 1
  • 3
  • 11
2

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();
        }
    }
});

Fiddle

L105
  • 5,091
  • 3
  • 16
  • 22
2

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/

Mehdi
  • 3,872
  • 4
  • 18
  • 34
2

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>
StefansArya
  • 2,108
  • 3
  • 15
  • 23
1
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'); //&nbsp;
   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');.

webprogrammer
  • 782
  • 14
  • 26
0

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();
      }
});

http://jsfiddle.net/jDvau/11/

MrAJ
  • 95
  • 4
  • It does not let the cursor move forward as you type. – Jack Lu Mar 13 '20 at 07:43
  • That is strange, I just tried in Chrome and IE 11 and it works fine. [Reference](https://imgur.com/CFqmJRH) Could you please tell me which browser you are using? Any more details about the behavior would be helpful for solving the issue – MrAJ Mar 18 '20 at 03:55
0

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.

Mohit Jain
  • 29,414
  • 8
  • 65
  • 93
0

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.

Hmerman6006
  • 606
  • 6
  • 17
-1

It is possible to prevent this behaviour entirely.

See this fiddle

$('<div class="temp-contenteditable-el" contenteditable="true"></div>').appendTo('body').focus().remove();
Omnicon
  • 314
  • 2
  • 9