JSFiddle - React, Tailwind, and code Playground

by waxwing

HTML

<script src="//cdnjs.cloudflare.com/ajax/libs/rangy/1.2.3/rangy-core.js"></script>
<div id="auto" contenteditable="true" class="text">
    This is a  &#8203;<span class="keyword" contenteditable="false">Keyword</span>. And also here is another  &#8203;<span class="keyword" contenteditable="false">one</span>.
</div>

CSS

.text {
    border: 1px solid black;
    padding: 10px;
    white-space: pre-wrap;
}

.keyword {
    background-color: #aaaaff;
    border: 1px solid #333399;
    border-radius: 2px;
}

JavaScript

rangy.init();

$.fn.allowUneditableContent = function () {

    var KEY_ENTER = 9;
    
    $(this).keypress(function (event) {
        var sel, node, offset, text, textBefore, textAfter, range;
        sel = rangy.getSelection();

        // the node that contains the caret
        node = sel.anchorNode;

        // if ENTER was pressed while the caret was inside the input field
        if (node.parentNode === this && event.which === 13) {

            // prevent br/div element
            event.preventDefault();

            // the caret position inside the node
            offset = sel.anchorOffset;        

            // insert a '\n' character at that position
            text = node.textContent;
            textBefore = text.slice( 0, offset );
            textAfter = text.slice( offset ) || ' ';
            node.textContent = textBefore + '\n' + textAfter;

            // position the caret after that new-line character
            range = document.createRange();
            range.setStart( node, offset + 1 );
            range.setEnd( node, offset + 1 );

            // update the selection
            sel.removeAllRanges();
            sel.addRange(range);
        }
    });
};

$("#auto").allowUneditableContent();