[JavaScript] Show tooltips when Hovering certain elements.

Hover over certain elements to display tooltips.
Requirements include

  • Display tooltips at hover timing
  • Displayed centred above a specific element
  • Display with a 200ms delay
  • Hides tooltips when hover ends

The completed image looks like this.

目次

Define HTML

This time, to display a tooltip when hovering a specific element, we add the data attribute to the DOM we want to display.

As it is a tooltip, we set it to ‘data-tooltip’.
This data-tooltip attribute is used to set the text you want the tooltip to display.

The HTML will look like this.

    <div style="width: fit-content; margin-top: 80px;">
        <div data-tooltip="ツールチップ">ホバーすると表示される</div>
    </div>

Define CSS

Decorate tooltips.

    .tooltip {
        position: absolute;
        background: #4b4848e0;
        color: #FFFFFF;
        font-size: 14px;
        line-height: 20px;
        padding: 8px 12px;
        border-radius: 4px;
        opacity: 0;
        transition: opacity 0.2s;
        pointer-events: none;
        transform: translateY(-8px);
        max-width: 184px;
    }

    .tooltip.show {
        opacity: 1;
    }

Implementing toolTip in JavaScript.

After the DOM has been loaded, a list of DOMs with the data-tooltip attribute is obtained and an event is attached to each DOM.

    document.addEventListener('DOMContentLoaded', () => {
        const tooltipContainers = document.querySelectorAll('[data-tooltip]');

        tooltipContainers.forEach(container => {
            let tooltipTimeout;
            let tooltipElement;

            container.addEventListener('mouseenter', () => {
                // show tooltip
            });

            container.addEventListener('mouseleave', () => {
                 // hide tooltip
            });
        });
    });

Write the mouseenter event.

When the mouseenter event occurs, the hover process is written after 200ms has elapsed with setTimeout.
Create the DOM for the tooltip with createElement, calculate the display position of the tooltip from the hovered element container, and set the tooltipElement style to be displayed as a tooltip.

As some DOM positions are misaligned, add window.scrollY etc. to the calculation if necessary.

            container.addEventListener('mouseenter', () => {
                tooltipTimeout = setTimeout(() => {
                    const tooltipText = container.getAttribute('data-tooltip');
                    tooltipElement = document.createElement('div');
                    tooltipElement.className = 'tooltip';
                    tooltipElement.innerText = tooltipText;
                    document.body.appendChild(tooltipElement);

                    const containerRect = container.getBoundingClientRect();
                    const tooltipRect = tooltipElement.getBoundingClientRect();

                    const top = containerRect.top - tooltipRect.height - 8;
                    const left = containerRect.left + (containerRect.width / 2) - (tooltipRect.width / 2);

                    tooltipElement.style.top = `${top}px`;
                    tooltipElement.style.left = `${left}px`;

                    requestAnimationFrame(() => {
                        tooltipElement.classList.add('show');
                    });
                }, 200);
            });

Write the mouseleave event.

At the timing when it is no longer hovered, clearTimeout is called to remove the timeout set. It is then hidden by deleting the show class.
Furthermore, the DOM of the temporarily created tooltip is deleted.

            container.addEventListener('mouseleave', () => {
                clearTimeout(tooltipTimeout);
                if (tooltipElement) {
                    tooltipElement.classList.remove('show');
                    tooltipElement.addEventListener('transitionend', () => {
                        if (tooltipElement.parentElement) {
                            tooltipElement.parentElement.removeChild(tooltipElement);
                        }
                    }, { once: true });
                }
            });

The JavaScript is summarised below.

    document.addEventListener('DOMContentLoaded', () => {
        const tooltipContainers = document.querySelectorAll('[data-tooltip]');

        tooltipContainers.forEach(container => {
            let tooltipTimeout;
            let tooltipElement;

            container.addEventListener('mouseenter', () => {
                tooltipTimeout = setTimeout(() => {
                    const tooltipText = container.getAttribute('data-tooltip');
                    tooltipElement = document.createElement('div');
                    tooltipElement.className = 'tooltip';
                    tooltipElement.innerText = tooltipText;
                    document.body.appendChild(tooltipElement);

                    const containerRect = container.getBoundingClientRect();
                    const tooltipRect = tooltipElement.getBoundingClientRect();

                    const top = containerRect.top - tooltipRect.height - 8;
                    const left = containerRect.left + (containerRect.width / 2) - (tooltipRect.width / 2);

                    tooltipElement.style.top = `${top}px`;
                    tooltipElement.style.left = `${left}px`;

                    requestAnimationFrame(() => {
                        tooltipElement.classList.add('show');
                    });
                }, 200);
            });

            container.addEventListener('mouseleave', () => {
                clearTimeout(tooltipTimeout);
                if (tooltipElement) {
                    tooltipElement.classList.remove('show');
                    tooltipElement.addEventListener('transitionend', () => {
                        if (tooltipElement.parentElement) {
                            tooltipElement.parentElement.removeChild(tooltipElement);
                        }
                    }, { once: true });
                }
            });
        });
    });

Summary

The setTimeout and the handling of the clearTimeout was a personal gimmick.

よかったらシェアしてね!
目次