JSFiddle - React, Tailwind, and code Playground
by Derek Leung
HTML
<div id="input"></div>
CSS
#input {
border: 2px inset #DDD;
width: 500px;
height: 14px;
padding: 2px 0px;
margin: 2px;
font-size: 12px;
font-family:'Arial';
white-space: nowrap;
overflow: hidden;
}
JavaScript
$("#input").prop("contentEditable", true).on("input", function (){
var loc = getCaretLocation(this);
$(this).contents().each(function(){
var current = this;
if(this.nodeType == 3 || this.nodeName == "FONT"){
$.each($(this).text().split(""), function(){
$("<span>").text(this).css({
color: "#"+(Math.random()*16777215|0).toString(16)
}).insertBefore(current);
});
$(this).remove();
}else{
var crtTxt = $(current).text();
if(crtTxt.length > 1){
for(var i = crtTxt.length - 1; i > 0; i--){
$("<span>").text(crtTxt[i]).css({
color: "#"+(Math.random()*16777215|0).toString(16)
}).insertAfter(current);
}
$(current).text(crtTxt[0]);
}
}
});
setCaretLocation(this, loc);
});
function setCaretLocation(ele, pos){
var range = document.createRange(),
sel = window.getSelection();
range.setStart(ele.childNodes[pos - 1], 1);
range.collapse(true);
sel.removeAllRanges();
sel.addRange(range);
}
function getCaretLocation(element) {
var range = window.getSelection().getRangeAt(0),
preCaretRange = range.cloneRange();
preCaretRange.selectNodeContents(element);
preCaretRange.setEnd(range.startContainer, range.startOffset);
return preCaretRange.toString().length;
}