JSFiddle - React, Tailwind, and code Playground
Caret and range selection pointer
by tonytlwu
HTML
<h4>Challenge</h4>
<p>To detect user's caret and selection position so that elements can be placed accordingly.</p>
<div contenteditable>
<h3>
Justo Condimentum Magna Pellentesque
</h3>
<p>Donec id elit non mi porta gravida at eget metus. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Morbi leo risus, porta ac consectetur
ac, vestibulum at eros.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi leo risus, porta ac consectetur ac, vestibulum at eros. Donec id elit non mi porta gravida at eget metus.</p>
<ul>
<li>Praesent commodo cursus magna, vel scelerisque nisl consectetur et.</li>
<li>Vestibulum id ligula porta felis euismod semper.</li>
<li>Etiam porta sem malesuada magna mollis euismod.</li>
</ul>
<p>
<button>Button 1</button>
</p>
</div>
<hr />
<h4>Result</h4>
<pre id="debug"></pre>
<div class="pointer pointer-caret"></div>
<div class="pointer pointer-range pointer-range-start"></div>
<div class="pointer pointer-range pointer-range-end"></div>
CSS
body {
font-family: sans-serif;
}
hr {
border-left: none;
border-right: none;
margin: 20px 0;
}
[contenteditable] {
padding: 10px;
border: 1px solid #e9e9e9;
}
[contenteditable]:hover {
border-color: #d9d9d9;
}
button {
-webkit-user-select: none;
}
.pointer {
position: fixed;
top: -9999px;
left: -9999px;
}
.pointer-caret {
width: 0;
height: 0;
border-style: solid;
border-width: 10px 10px 0 10px;
border-color: #ff0000 transparent transparent transparent;
}
.pointer-range-start {
width: 0;
height: 0;
border-style: solid;
border-width: 0 10px 10px 0;
border-color: transparent #ff0000 transparent transparent;
}
.pointer-range-end {
width: 0;
height: 0;
border-style: solid;
border-width: 10px 10px 0 0;
border-color: #ff0000 transparent transparent transparent;
}
JavaScript
$('[contenteditable]').on('focus blur change update paste input keyup mouseup', function() {
var selection = window.getSelection();
var selectionType = selection.type;
var selectionRange = selection.getRangeAt(0);
var selectionRangeRect = selectionRange.getBoundingClientRect();
var log = '';
log += selectionType + ': ';
log += Math.round(selectionRangeRect.left) + 'px, ' + Math.round(selectionRangeRect.top) + 'px; ';
log += Math.round(selectionRangeRect.width) + 'px x ' + Math.round(selectionRangeRect.height) + 'px'
$('#debug').html(log);
$('.pointer').css({
top: '',
left: ''
});
switch (selectionType.toLowerCase()) {
case 'range':
$('.pointer-range-start').css({
top: Math.round(selectionRangeRect.top) - 10 + 'px',
left: Math.round(selectionRangeRect.left) - 10 + 'px'
});
$('.pointer-range-end').css({
top: Math.round(selectionRangeRect.top) - 10 + 'px',
left: Math.round(selectionRangeRect.left + selectionRangeRect.width) + 'px'
});
break;
case 'caret':
$('.pointer-caret').css({
top: Math.round(selectionRangeRect.top) - 10 + 'px',
left: Math.round(selectionRangeRect.left) - 10 + 'px'
});
break;
}
});