JSFiddle - React, Tailwind, and code Playground

HTML

<html>
<body>
    <div>
        <textarea>my text area</textarea>
    </div>
    <div id="pos">Pos: <span></span></div>
</body>
</html>

CSS

textarea {
    width: 300px;
    height: 100px;
    font-size: 25px;
    font-family: Helvetica, Arial, Verdana;
}

body {
  padding: 50px 100px
}

.cursor {
    width:5px;
    height:30px;
    background-color: #f00;
    opacity: 0.5;
    position: absolute;
    z-index:10000;
}

JavaScript

// http://stackoverflow.com/questions/263743/how-to-get-caret-position-in-textarea
function getCaret(el) { 
  if (el.selectionStart) { 
    return el.selectionStart; 
  } else if (document.selection) { 
    el.focus(); 

    var r = document.selection.createRange(); 
    if (r == null) { 
      return 0; 
    } 

    var re = el.createTextRange(), 
        rc = re.duplicate(); 
    re.moveToBookmark(r.getBookmark()); 
    rc.setEndPoint('EndToStart', re); 

    return rc.text.length; 
  }  
  return 0; 
}


$(function(){
    var span = $('#pos span');
    var textarea = $('textarea');
    
    var clone = $('<div/>').appendTo('body');
    clone.width(textarea.width());
    clone.height(textarea.height());
    clone.css('max-height', textarea.height() + "px");
    clone.css('word-wrap', 'break-word');
    clone.css('word-break', 'break-all');
    var style = document.defaultView.getComputedStyle(textarea[0],null);

    clone.css("font",style.font);    
    
    var fakeCursor = $("<div/>")
        .hide()
        .addClass('cursor')
        .appendTo(textarea.parent());
    
    textarea.on('keydown keyup click', function(event) {
        var pos = getCaret(textarea[0]),
            which = event.which;
        
        span.text(pos);
        
        var v = textarea.val().substring(0, pos);
        
        var buf = "";
        for(var i=0; i < v.length; i++) {
            var c = v[i];

            c = c.replace("<", "&lt;");
            c = c.replace(">", "&gt;");
            c = c.replace(" ", "&nbsp;");
            c = c.replace("\r", "");
            c = c.replace("\n", "<br>");
        
            buf += c;
        }
        clone.html(buf); 
        
        var cursor = $("<span>«</span>");
        clone.append(cursor);
        pos = cursor.position();
        
        fakeCursor.css({
            left: pos.left,
            top: pos.top - clone.position().top + textarea.position().top - textarea.scrollTop()
        }).show();
    });
});