JSFiddle - React, Tailwind, and code Playground
HTML
<div id="info">
</div>
<div id="editable" contenteditable="true" onkeyup="getCaret()">
</div>
CSS
#editable {
width: 100%;
height: 400px;
background: #333;
color: #fff;
padding: 20px;
}
#info {
height: 60px;
}
JavaScript
function getCaret() {
const editable = document.getElementById('editable');
// collapse selection to end
window.getSelection().collapseToEnd();
const sel = window.getSelection();
const range = sel.getRangeAt(0);
// get anchor node if startContainer parent is editable
let selectedNode = editable === range.startContainer.parentNode
? sel.anchorNode
: range.startContainer.parentNode;
if (!selectedNode) {
document.getElementById('info').innerText = `caret: 0, line: 0`;
return;
}
// select to top of editable
range.setStart(editable.firstChild, 0);
// do not use 'this' sel anymore since the selection has changed
const content = window.getSelection().toString();
const text = JSON.stringify(content);
const lines = (text.match(/\\n/g) || []).length + 1;
// clear selection
window.getSelection().collapseToEnd();
document.getElementById('info').innerText = `caret: ${text.length - 2}, line: ${lines}`;
}