JSFiddle - React, Tailwind, and code Playground
HTML
<script src="https://cdnjs.cloudflare.com/ajax/libs/tether/1.1.0/js/tether.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/interact.js/1.2.5/interact.js"></script>
<span id="target">drag me</span>
<span id="element"><i id="arrow"></i>popover</span>
CSS
span {
padding: 0.5em;
}
#target {
position: absolute;
left: 50%;
border: 2px solid black;
border-radius: 20px;
width: 76px;
box-sizing: border-box;
text-align: center;
}
#element {
position: absolute;
width: 100px;
height: 100px;
color: white;
background-color: black;
}
#element #arrow {
content: " ";
position: absolute;
top: -10px;
width: 0;
height: 0;
border-left: 10px solid transparent;
border-right: 10px solid transparent;
border-bottom: 10px solid black;
left: 50%;
margin-left: -10px;
}
#element.tether-element-attached-center #arrow {
transform: translateX(0) !important;
}
JavaScript
interact('#target')
.draggable({
onmove: function dragMoveListener (event) {
var target = event.target;
var x = (parseFloat(target.getAttribute('data-x')) || 0) + event.dx;
var y = (parseFloat(target.getAttribute('data-y')) || 0) + event.dy;
target.style.transform = 'translate(' + x + 'px, ' + y + 'px)';
target.setAttribute('data-x', x);
target.setAttribute('data-y', y);
arrowOffset = 0;
arrowOffset = target.getBoundingClientRect().left - element.getBoundingClientRect().left - 20;
arrow.style.transform = 'translateX(' + arrowOffset + 'px)';
tether()
}
});
function tether() {
new Tether({
element: document.getElementById("element"),
target: document.getElementById("target"),
attachment: 'middle right',
targetAttachment: 'middle left',
constraints: [
{
to: 'window',
attachment: 'none element',
pin: ['left', 'right', 'center']
}
],
targetOffset: "10px 10px"
});
}
tether();