Implement tooltip component

You are required to Implement an Tooltip component.

A tooltip is a floating, non-actionable informative label used to explain a UI element or feature. It's appears when users hover over, focus on, or tap an element.

This is initial structure of HTML:

<div data-tooltip="Name description">Hi, my name is John</div>

Requirements:

  • Show tooltip on hover on element with attribute data-tooltip
  • Maintain multiple tooltips per page
  • Take content of the toolitp from data-tooltip attribute. It could be HTML
  • Optimisations
    • Show tooltip with some delay, e.g. 500ms

Solution

<style>
  [data-tooltip] {
    text-decoration: underline;
    cursor: help;
  }

  [role="tooltip"] {
    opacity: 0;
    position: absolute;
    width: auto;
    height: auto;
  }

  [role="tooltip"].active {
    opacity: 1;
    transform: translateX(-50%); /* Center tooltip according parent element*/
  }
</style>

<div>
  Many species of gecko have
  <span data-tooltip="Hi there!">adhesive</span> toe pads which enable them to climb walls and even windows.
</div>
const tooltips = document.querySelectorAll("[data-tooltip]");
const DELAY = 300;
let tooltipTimer = null;

const createTooltip = (target) => {
  let tooltip = document.createElement("div");

  tooltip.setAttribute("role", "tooltip");
  tooltip.setAttribute("inert", true);
  tooltip.textContent = target.dataset.tooltip;

  target.appendChild(tooltip);
};

const displayTooltip = (evt) => {
  const target = evt.target;
  const tooltip = target.querySelector("[role=tooltip]");

  // Get the target element's position and dimensions
  const { x, y, width, height } = target.getBoundingClientRect();

  // Set the tooltip position to be centered above the target element
  tooltip.style.left = `${Math.floor(x + width / 2)}px`;
  tooltip.style.top = `${Math.floor(y + height)}px`;

  tooltip.classList.add("active");
};

const hideTooltip = (evt) => {
  const tooltip = evt.target.querySelector("[role=tooltip]");
  tooltip.classList.remove("active");
};

tooltips.forEach((target) => {
  createTooltip(target);

  target.addEventListener("mouseenter", (e) => {
    clearTimeout(tooltipTimer);

    tooltipTimer = setTimeout(() => {
      displayTooltip(e);
    }, DELAY);
  });

  target.addEventListener("mouseleave", (e) => {
    clearTimeout(tooltipTimer);
    hideTooltip(e);
  });
});