JSFiddle - React, Tailwind, and code Playground

HTML

The word colored will be formated as <font color="red">colored</font>, and the word highlighting will be formated as <span style="background-color: yellow">highlighting</span> in real time.

<div id="textarea" contenteditable>This is an editable <font color="red">colored</font> text area with <span style="background-color: yellow">highlighting</span>.</div>

CSS

#textarea {
    -moz-appearance: textfield-multiline;
    -webkit-appearance: textarea;
    border: 1px solid gray;
    font: medium -moz-fixed;
    font: -webkit-small-control;
    font-family: "Courier New", monospace;
    height: 50px;
    overflow: auto;
    padding: 2px;
    resize: both;
    width: 400px;
}

JavaScript

$(function(){
    var prevText = "";
    var isHighlighting = false;
    $("#textarea").bind("paste drop keypress input textInput DOMNodeInserted", function (e){
        if (!isHighlighting)
        {
            var currentText = $(this).text();
            if (currentText != prevText)
            {
                doSave();
                isHighlighting = true;
                $(this).html(currentText
                       .replace(/\bcolored\b/g, "<font color=\"red\">colored</font>")
                       .replace(/\bhighlighting\b/g, "<span style=\"background-color: yellow\">highlighting</span>"));
                isHighlighting = false;
                prevText = currentText;
                doRestore();
            }
        }
    });
});

var saveSelection, restoreSelection;

if (window.getSelection && document.createRange) {
    saveSelection = function(containerEl) {
        var range = window.getSelection().getRangeAt(0);
        var preSelectionRange = range.cloneRange();
        preSelectionRange.selectNodeContents(containerEl);
        preSelectionRange.setEnd(range.startContainer, range.startOffset);
        var start = preSelectionRange.toString().length;

        return {
            start: start,
            end: start + range.toString().length
        }
    };

    restoreSelection = function(containerEl, savedSel) {
        var charIndex = 0, range = document.createRange();
        range.setStart(containerEl, 0);
        range.collapse(true);
        var nodeStack = [containerEl], node, foundStart = false, stop = false;
        
        while (!stop && (node = nodeStack.pop())) {
            if (node.nodeType == 3) {
                var nextCharIndex = charIndex + node.length;
                if (!foundStart && savedSel.start >= charIndex && savedSel.start <= nextCharIndex) {
                    range.setStart(node, savedSel.start - charIndex);
                    foundStart = true;
                }
                if (foundStart &&...