skip to Main Content

I have a nested structure of div elements where the innermost child contains a tooltip. The parent container (parent class) has the CSS property overflow: hidden. However, when hovering over the tooltip, it gets clipped and doesn’t overflow outside the boundaries of the parent. Here’s a simplified version of the structure:

document.querySelectorAll(".tooltip_container").forEach((tooltip) => {
  const tooltipText = tooltip.getAttribute("data-tooltip");
  const tooltipContent = document.createElement("div");
  tooltipContent.className = "tooltip_content";
  tooltipContent.innerText = tooltipText;

  tooltip.appendChild(tooltipContent);

});
.parent_class {
  position: relative;
  width: 300px;
  height: 100px;
  margin: 50px;
  overflow: auto;
  border: 2px solid #ccc;
  padding: 20px;
  background-color: #f9f9f9;
}

.child_level_four {
  position: relative;
  margin-top: 0px;
  display: flex;
  flex-direction: column;
  gap: 16px;
}


.tooltip_container {
  position: relative;
  display: inline-block;
}

.tooltip_content {
  position: absolute;
  bottom: 100%;
  left: -15%;
  transform: translateX(-50%);
  background-color: #333;
  color: #fff;
  padding: 8px;
  border-radius: 4px;
  opacity: 0;
  visibility: hidden;
  white-space: nowrap;
  transition: all 0.3s ease-in-out;
  z-index: 1000;
}

.tooltip_content::after {
  content: '';
  position: absolute;
  top: 100%;
  left: 50%;
  transform: translateX(-50%);
  border-width: 5px;
  border-style: solid;
  border-color: #333 transparent transparent transparent;
}

.tooltip_container:hover .tooltip_content {
  opacity: 1;
  visibility: visible;
  transform: translateY(-18%);
}
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Pure JS Tooltip</title>
  <link rel="stylesheet" href="styles.css">
</head>
<body>
  <div class="parent_class">
    <div class="child_level_one">
      <div class="child_level_two">
        <div class="child_level_three">
          <div class="child_level_four">
            <div class="tooltip_container" data-tooltip="Overflow Tooltip Text">
              <button>Hover Me</button>
            </div>
            <div class="tooltip_container" data-tooltip="Overflow Tooltip Text">
              <button>Hover Me</button>
            </div>
            <div class="tooltip_container" data-tooltip="Overflow Tooltip Text">
              <button>Hover Me</button>
            </div>
            <div class="tooltip_container" data-tooltip="Overflow Tooltip Text">
              <button>Hover Me</button>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>

  <script src="script.js"></script>
</body>
</html>

2

Answers


  1. That is not trivial. We need to append to body and make a sort of mouse follow:

    document.querySelectorAll(".tooltip_container").forEach((tooltip) => {
      const tooltipText = tooltip.getAttribute("data-tooltip");
    
      const tooltipContent = document.createElement("div");
      tooltipContent.className = "tooltip_content";
      tooltipContent.innerText = tooltipText;
    
      // Append tooltip to the body
      document.body.appendChild(tooltipContent);
    
      tooltip.addEventListener("mouseenter", (event) => {
        tooltipContent.style.visibility = "visible";
        tooltipContent.style.opacity = "1";
    
        // Position tooltip initially
        updateTooltipPosition(event);
      });
    
      tooltip.addEventListener("mouseleave", () => {
        tooltipContent.style.visibility = "hidden";
        tooltipContent.style.opacity = "0";
      });
    
      tooltip.addEventListener("mousemove", (event) => {
        updateTooltipPosition(event);
      });
    
      function updateTooltipPosition(event) {
        const offset = 10; // Offset to avoid flickering - since mousing over the tooltip triggers mouseleave
        const tooltipWidth = tooltipContent.offsetWidth;
        const tooltipHeight = tooltipContent.offsetHeight;
    
        let top = event.clientY - tooltipHeight - offset;
        let left = event.clientX - tooltipWidth / 2;
    
        // Prevent tooltip from going out of the viewport
        if (top < 0) top = event.clientY + offset; // Position below if it goes above
        if (left < 0) left = offset; // Align to the left edge
        if (left + tooltipWidth > window.innerWidth)
          left = window.innerWidth - tooltipWidth - offset; // Align to the right edge
    
        tooltipContent.style.top = `${top}px`;
        tooltipContent.style.left = `${left}px`;
      }
    });
    .parent_class {
      position: relative;
      width: 300px;
      height: 100px;
      margin: 50px;
      overflow: auto;
      border: 2px solid #ccc;
      padding: 20px;
      background-color: #f9f9f9;
    }
    
    .child_level_four {
      position: relative;
      margin-top: 0px;
      display: flex;
      flex-direction: column;
      gap: 16px;
    }
    
    
    .tooltip_container {
      position: relative;
      display: inline-block;
      z-index: 1000;
    }
    
    .tooltip_content {
      position: absolute;
      background-color: #333;
      color: #fff;
      padding: 8px;
      border-radius: 4px;
      opacity: 0;
      visibility: hidden;
      white-space: nowrap;
      transition: opacity 0.3s ease-in-out;
      z-index: 9999;
    }
    
    .tooltip_content::after {
      content: '';
      position: absolute;
      top: 100%;
      left: 50%;
      transform: translateX(-50%);
      border-width: 5px;
      border-style: solid;
      border-color: #333 transparent transparent transparent;
    }
    
    
    .tooltip_container:hover .tooltip_content {
      opacity: 1;
      visibility: visible;
      transform: translateY(-18%);
    }
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Pure JS Tooltip</title>
      <link rel="stylesheet" href="styles.css">
    </head>
    <body>
      <div class="parent_class">
        <div class="child_level_one">
          <div class="child_level_two">
            <div class="child_level_three">
              <div class="child_level_four">
                <div class="tooltip_container" data-tooltip="Overflow Tooltip Text">
                  <button>Hover Me</button>
                </div>
                <div class="tooltip_container" data-tooltip="Overflow Tooltip Text">
                  <button>Hover Me</button>
                </div>
                <div class="tooltip_container" data-tooltip="Overflow Tooltip Text">
                  <button>Hover Me</button>
                </div>
                <div class="tooltip_container" data-tooltip="Overflow Tooltip Text">
                  <button>Hover Me</button>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    
      <script src="script.js"></script>
    </body>
    </html>
    Login or Signup to reply.
  2. This happen because the overflow: hidden attribute on .parent_class truncates any information that exceeds its borders, including your tooltip. Here is the simple way to make the tooltip visible:

    Change the tooltip’s position to fixed. This positions it relative to the viewport instead of the parent container, bypassing the overflow: hidden issue.

    .tooltip_content {
        /* position: absolute;
        bottom: 100%;
        left: -50%;
        transform: translateX(-50%);*/
        position: fixed; /* Position relative to viewport */
        bottom: auto;    /* Adjust position for viewport */
        left: auto;
        transform: none; /* Remove or adjust transform */
        background-color: #333;
        color: #fff;
        padding: 8px;
        border-radius: 4px;
        opacity: 0;
        visibility: hidden;
        white-space: nowrap;
        transition: all 0.3s ease-in-out;
        z-index: 1000;
      }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search