How to change behavior of contenteditable blocks after on enter pressed in various browsers

19,040

Solution 1

As Douglas said earlier, browsers try to clone previous tag when customer starts a new paragraph on an editable page. The discrepancy occurs when browser has nothing to depart from - e.g. when initially the page body is empty. In this case different browsers behave differently: IE starts to wrap every string into <p> tag, Chrome wraps each line in <div>.

To increase cross-browser experience, WebKit developers have introduced the DefaultParagraphSeparator command. You can use the following JavaScript on page loading for Chrome to change default paragraph separator to <p> tag:

document.execCommand('defaultParagraphSeparator', false, 'p');

Solution 2

The following will add a <br> when the enter key is pressed in all major browsers and attempts to place the caret directly after it. However, WebKit, Opera and IE all have issues with placing the caret correctly after the <br>, which the following code does not attempt to correct.

function enterKeyPressHandler(evt) {
    var sel, range, br, addedBr = false;
    evt = evt || window.event;
    var charCode = evt.which || evt.keyCode;
    if (charCode == 13) {
        if (typeof window.getSelection != "undefined") {
            sel = window.getSelection();
            if (sel.getRangeAt && sel.rangeCount) {
                range = sel.getRangeAt(0);
                range.deleteContents();
                br = document.createElement("br");
                range.insertNode(br);
                range.setEndAfter(br);
                range.setStartAfter(br);
                sel.removeAllRanges();
                sel.addRange(range);
                addedBr = true;
            }
        } else if (typeof document.selection != "undefined") {
            sel = document.selection;
            if (sel.createRange) {
                range = sel.createRange();
                range.pasteHTML("<br>");
                range.select();
                addedBr = true;
            }
        }

        // If successful, prevent the browser's default handling of the keypress
        if (addedBr) {
            if (typeof evt.preventDefault != "undefined") {
                evt.preventDefault();
            } else {
                evt.returnValue = false;
            }
        }
    }
}

var el = document.getElementById("your_editable_element");

if (typeof el.addEventListener != "undefined") {
    el.addEventListener("keypress", enterKeyPressHandler, false);
} else if (typeof el.attachEvent != "undefined") {
    el.attachEvent("onkeypress", enterKeyPressHandler);
}

Solution 3

Excellent references are located here on contenteditable.

http://blog.whatwg.org/the-road-to-html-5-contenteditable

Which leads to a really nice API here http://dev.opera.com/articles/view/rich-html-editing-in-the-browser-part-1/ http://dev.opera.com/articles/view/rich-html-editing-in-the-browser-part-2/

If you're willing to take 30 minutes to an hour to read all this, you will absolutely not have to use some crappy third party editor like tinyMCE or ckeditor or whatever, you can build and customize it yourself and to be frank, it's easier AND faster to do it from scratch than to deal with all the cruft and unnecessary API of a third party WYSIWYG editor.

Solution 4

If you prefer to be happy rather than chase bugs :-) it would be much better to try to make FF use p or div as well. Not just besause it turned out to be a majority vote :-)

The reason is that br alone is borderline illegal if you look at a tag with XML eyes (it injects mixed data model - as in a text that's not guarded by a tag) and the thrend has been for years (by all browsers) towards full XML-ization.

Depending on your actual app it might be worth to try to put a div with fully formed style and definitely with some initial content - if you saw pages where you see grayed-out text like "type your comment here" and it dissapears the second you click into it (or remians - that's a design decision).

The reason for that part is that the semantics of "contenteditable" is "it already has content => browser has enough info to know what to do" so while browsers do their best to do something when faced with no content it makes the situation much more random.

Solution 5

I believe that if the div already has a paragraph tag inside it, and the user presses return while focus is inside that paragraph tag, then Firefox will insert another one. So, if you have this:

<div contenteditable="true">
    <p>&nbsp;</p>
    <p>&nbsp;</p>
</div>

and you focus, the press return, Firefox will insert a third paragraph.

You might be able to get around having the & nbsp ; in the paragraph tags by giving them minimum heights, and you might be able to get away with having only one. I never got to the bottom of the behaviour to my satisfaction the last time I looked at this. You'll probably need some JavaScript to enforce a minimum of one paragraph tag inside the div.

Share:
19,040
liysd
Author by

liysd

Updated on July 13, 2022

Comments

  • liysd
    liysd almost 2 years

    When pressing enter in <div contenteditable="true"> </div> in firefox <br /> is produced - that's ok. But in Chrome or IE a new <div> or <p> is created. What should I do to make Chrome and IE behave like Firefox .

  • Tim Down
    Tim Down over 11 years
    I strongly disagree with this. Unless your requirements are very basic, one of the good off-the-shelf editors such as TinyMCE and CKEditor will do a lot better than a quickly-assembled home-brewed solution. The difficulties in developing a WYSIWYG editor are perhaps not obvious but I can assure you they exist and are serious.
  • Horen
    Horen over 11 years
    +1: This works very well in most cases. However it breaks the default behaviour in <ul /> and <ol /> where pressing the enter key would normally insert a new list item <li />. Is there any workaround for that?
  • Tim Down
    Tim Down over 11 years
    @Horen: The workaround would be to add a special case to the code to deal with this. I'd be tempted to look at the source code for one of the big editors like CKEditor or TinyMCE to see how they handle it.
  • Roko C. Buljan
    Roko C. Buljan over 11 years
    +1 for the "do it yourself will spare you time" which is is 90% of cases totally correct, and pushes one not only to download-use but also to be creative. But as mentioned by Tim - have always an eye for possible xb issues or other problems that might come on the way.
  • diegoreymendez
    diegoreymendez over 9 years
    Worked great for me in iOS. Thanks!
  • horse
    horse about 8 years
    Hi Douglas, that's correct: FF inserts new paragraphs when pressed return. But that's not true for div tag, so I have an initial div child, and FF inserts <br> on return. How can I make FF insert div's on return?
  • Max
    Max over 4 years
    It's too bad this command doesn't support br as an argument. Imagine you're editing a p tag, having another p inside is invalid, but having more br's is perfectly valid.