How to make HTML5 contenteditable div allowing only text in firefox?

Sadly, you can’t. As this answer points out the spec only specifies true, false and inherit as valid parameters. The subject seems to have been discussed but if I’m not mistaken only Webkit implements support for plaintext-only.


I ran into this problem myself. Here is my solution which I have tested in Firefox and Chrome:

Ensure the contenteditable div has the css white-space: pre, pre-line or pre-wrap so that it displays \n as new lines.

Override the "enter" key so that when we are typing, it does not create any <div> or <br> tags

myDiv.addEventListener("keydown", e => {
    //override pressing enter in contenteditable
    if (e.keyCode == 13)
    {
        //don't automatically put in divs
        e.preventDefault();
        e.stopPropagation();
        //insert newline
        insertTextAtSelection(myDiv, "\n");
    }
});

Secondly, override the paste event to only ever fetch the plaintext

//override paste
myDiv.addEventListener("paste", e => {
    //cancel paste
    e.preventDefault();
    //get plaintext from clipboard
    let text = (e.originalEvent || e).clipboardData.getData('text/plain');
    //insert text manually
    insertTextAtSelection(myDiv, text);
});

And here is the supporting function which inserts text into the textContent of a div, and returns the cursor to the proper position afterwards.

function insertTextAtSelection(div, txt) {
    //get selection area so we can position insert
    let sel = window.getSelection();
    let text = div.textContent;
    let before = Math.min(sel.focusOffset, sel.anchorOffset);
    let after = Math.max(sel.focusOffset, sel.anchorOffset);
    //ensure string ends with \n so it displays properly
    let afterStr = text.substring(after);
    if (afterStr == "") afterStr = "\n";
    //insert content
    div.textContent = text.substring(0, before) + txt + afterStr;
    //restore cursor at correct position
    sel.removeAllRanges();
    let range = document.createRange();
    //childNodes[0] should be all the text
    range.setStart(div.childNodes[0], before + txt.length);
    range.setEnd(div.childNodes[0], before + txt.length);
    sel.addRange(range);
}

https://jsfiddle.net/1te5hwv0/