JSFiddle - React, Tailwind, and code Playground
HTML
<div class="container">
<div style="top:20px;left:20px;" class="red-circle" data-content="This is a red circle"></div>
<div style="top:10px;left:150px;" class="red-circle" data-content="This is the top-right red circle"></div>
<div style="top:160px;left:150px;" class="red-circle" data-content="This is the bottom-right red circle"></div>
<span style="visibility:hidden" id="pop-up"></span>
</div>
CSS
.container {
width: 200px;
height: 200px;
border: 1px solid black;
position: relative;
}
.red-circle {
border-radius: 50%;
background: red;
width: 20px;
height: 20px;
position: absolute;
}
#pop-up {
background-color: #EFEFEF;
padding: 0.25em;
position: absolute;
box-sizing: border-box;
}
JavaScript
const popup = document.getElementById("pop-up")
const parsePx = (px) => parseFloat(px.slice(0, -2))
const showPopup = (top, left, text, container) => {
popup.textContent = text;
const containerBCR = container.getBoundingClientRect();
const popupBCR = popup.getBoundingClientRect();
const popupWidth = popupBCR.width,
popupHeight = popupBCR.height;
let popupTop = top + 20,
popupLeft = left + 20,
newPopupWidth;
console.log("height: ", popupHeight);
console.log("top: ", top);
console.log("bottomPopup: ", top + 20 + popupHeight);
console.log("bottomBoundary", containerBCR.bottom);
if (left + 20 + popupWidth > containerBCR.right) {
popupLeft = left - popupWidth;
if (popupLeft < containerBCR.left) {
popupLeft = containerBCR.left;
newPopupWidth = left - containerBCR.left;
}
}
if (top + 20 + popupHeight > containerBCR.bottom) {
popupTop = top - popupHeight;
if (popupTop < containerBCR.top) {
popupTop = containerBCR.top;
}
}
popup.style.top = popupTop + "px";
popup.style.left = popupLeft + "px";
popup.style.width = newPopupWidth;
popup.style.visibility = 'visible';
}
const hidePopup = () => {
popup.style.visibility = 'hidden';
}
const container = document.querySelector(".container");
const circles = document.querySelectorAll(".red-circle")
circles.forEach(el => el.addEventListener('mouseover', (e) => {
const hoveredEl = e.target;
const textContent = hoveredEl.getAttribute('data-content');
const { top, left } = getComputedStyle(hoveredEl);
showPopup(parsePx(top), parsePx(left), textContent, container);
}))
circles.forEach(el => el.addEventListener('mouseout', (e) => { hidePopup() }))