JSFiddle - React, Tailwind, and code Playground

by waxwing

HTML

<script src="//cdnjs.cloudflare.com/ajax/libs/knockout/2.3.0/knockout-min.js"></script>
<div id="auto" contenteditable="true" data-bind="bidiHtml: test" class="text">
    This is a <span class="keyword" contenteditable="false">Keyword</span>. And also here is another <span class="keyword" contenteditable="false">one</span>.
</div>

<select data-bind="options: fields, value: selectedField"></select>
<button data-bind="click: addField">Add</button>

CSS

.text {
    border: 1px solid black;
    padding: 10px;
}

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

JavaScript

ko.bindingHandlers.bidiHtml = {
    init: function (element, valueAccessor) {
        var obs = valueAccessor();
        ko.utils.registerEventHandler(element, 'input', function () {
            obs(this.innerHTML);
        });
    },
    update: function (element, valueAccessor) {
        var obs = valueAccessor();
        console.log(obs(), element.innerHTML);
        if (obs() !== element.innerHTML) {
            ko.utils.setHtml(element, obs);
        }
    }
}


var model = {
    fields: [ "Lead actor", "Production cost", "Record name", "Date published" ],
    selectedField: ko.observable(),
    addField: function () {
        this.test(this.test() +
                  '<span class="keyword">' + 
                  this.selectedField() +
                  '</span>');
    },
    test: ko.observable('')
};

$("#auto").autocomplete({
    source: function(request, response) {
        var words = request.term.split(/\s+/);
        var term = words[words.length];
        
    },
    focus: function() {
        // prevent value inserted on focus
        return false;
    },
    select: function( event, ui ) {
        var terms = split( this.value );
        // remove the current input
        terms.pop();
        // add the selected item
        terms.push( ui.item.value );
        // add placeholder to get the comma-and-space at the end
        terms.push( "" );
        this.value = terms.join( ", " );
        return false;
    }
});