Create tooltips with pure JavaScript

We are going to create a plugin that can show nice tooltips in this tutorial, this is done with pure JavaScript. A tooltip is a small message that is supposed to help a user to enter a valid value in an input element.

This plugin is supposed to work on all devices and on all screen sizes. A tooltip will be shown on mouseenter or a click, a visible tooltip will disappear on mouseleave or a click. Tooltips is shown below the target as default but will be shown over the target if the tooltip is below the visible viewport.

This plugin has been tested and is working with Google Chrome (75.0.3770.100), Mozilla Firefox (67.0.4) and Microsoft Edge (42.17134.1.0), without any polyfill. It works in Internet Explorer (11.829.17134.0) with a polyfill for Element.prototype.closest and Element.prototype.remove. If you want to support older browsers, check out our post on transpilation and polyfilling of JavaScript.

Tooltip

JavaScript

This plugin is static and only have private methods, it relies entirely on events. Event listeners is added for elements that has tooltip as a rel attribute, the tooltip is added inside the tags of the element.

(function () {

    'use_strict';

    // Get all targets
    var targets = document.querySelectorAll('[rel="tooltip"]');

    // Loop targets
    for (var i = 0; i < targets.length; i++) {

        // Add listeners
        targets[i].addEventListener('mouseenter', function ()
        {
            addTooltip(this, document.querySelector('.annytab-tooltip'));

        }, false);
        targets[i].addEventListener('mouseleave', function ()
        {
            removeTooltip(this, document.querySelector('.annytab-tooltip'));

        }, false);
        targets[i].addEventListener('click', function () {

            // Get the active tooltip
            var tooltip = document.querySelector('.annytab-tooltip');

            // Get the target
            var target = event.target.closest('[rel="tooltip"]');

            // Check if the tooltip exists or not
            if (tooltip === null)
            {
                // Add a tooltip
                addTooltip(target, tooltip);
            }
            else
            {
                // Remove a tooltip
                removeTooltip(target, tooltip);
            }

        }, false);

    } // End of for (var i = 0; i < targets.length; i++)

    // Add a tooltip
    function addTooltip(target, tooltip)
    {
        // Get the title
        var title = target.getAttribute('title');

        // Make sure that title not is null or empty
        if (title === null || title === '' || tooltip !== null)
        {
            return false;
        }

        // Remove the title of the target
        target.removeAttribute('title');

        // Add a tooltip
        tooltip = document.createElement('div');
        tooltip.setAttribute('class', 'annytab-tooltip');
        tooltip.innerHTML = title;
        target.insertAdjacentElement('beforeend', tooltip);

        // Initiate the tooltip
        tooltip.style.right = '0px';
        tooltip.style.top = target.offsetTop + target.offsetHeight + 10 + 'px';
        var bounding = tooltip.getBoundingClientRect();

        // Check if the tooltip is below the viewport
        if (bounding.bottom > (window.innerHeight || document.documentElement.clientHeight))
        {
            tooltip.style.top = '';
            tooltip.style.bottom = target.offsetTop + target.offsetHeight + 10 + 'px';
            tooltip.classList.add('top');
        }
        else
        {
            tooltip.classList.add('bottom');
        }

    } // End of the addTooltip method

    // Remove a tooltip
    function removeTooltip(target, tooltip)
    {
        if (tooltip !== null)
        {
            // Reset the title and remove the tooltip
            target.setAttribute('title', tooltip.innerHTML);
            tooltip.remove();
        }
        
    } // End of the removeTooltip method

})();

Styling (CSS)

A tooltip is added with a annytab-tooltip class and can be placed at the bottom of the target or at the top of the target. No styling for box-sizing is added here, box-size styling makes elements size correctly in browsers.

.annytab-tooltip {
    text-align: left;
    color: #ffffff;
    background: #000000;
    position: absolute;
    z-index: 100;
    font-size: 16px;
    line-height: 24px;
    padding: 15px;
    max-width: 100%;
    border-radius: 4px;
    border: 1px solid #000000;
}
.annytab-tooltip.bottom::after {
    position: absolute;
    width: 0;
    height: 0;
    border-left: 10px solid transparent;
    border-right: 10px solid transparent;
    border-bottom: 10px solid #000000;
    content: '';
    top: -11px;
    right: 10px;
}
.annytab-tooltip.top::after {
    position: absolute;
    width: 0;
    height: 0;
    border-left: 10px solid transparent;
    border-right: 10px solid transparent;
    border-top: 10px solid #000000;
    content: '';
    bottom: -11px;
    right: 10px;
}

How to use this plugin

We add a div element with an icon, a title and a tooltip rel attribute after each input that should have a tooltip. The tooltip will be added inside this element, this is important to avoid a flickering behavior. Polyfills is needed for this plugin to work in Internet Explorer 11 and older browsers.

<!DOCTYPE html>
<html>
<head>
    <title>Tooltips</title>
    <style>
        input, div, a, textarea, select {
            -webkit-box-sizing: border-box;
            -moz-box-sizing: border-box;
            box-sizing: border-box;
            font-family: Arial, Helvetica, sans-serif;
        }
        .annytab-form-label {
            display: block;
            width: 100%;
            max-width: 500px;
            padding: 0px 2px 0px 2px;
            font-size: 16px;
            line-height: 24px;
            font-weight: bold;
            margin: 10px 0px 0px 0px;
        }
        .annytab-input-group {
            display: table;
            position: relative;
            width: 100%;
            max-width: 500px;
            padding: 0px;
            margin: 10px 0px 0px 0px;
            border: 1px solid #d9d9d9;
            border-radius: 8px;
            height: 34px;
        }

        .input-group-cell {
            display: table-cell;
            text-align: center;
            padding: 0px;
            vertical-align: middle;
        }

        .input-group-control {
            display: block;
            background-color: transparent;
            width: 100%;
            border: 0px;
            margin: 0px;
            font-size: 16px;
            line-height: 16px;
            padding: 10px 5px 10px 5px;
        }
    </style>
</head>
<body style="width:100%;font-family:Arial, Helvetica, sans-serif;">

    <div style="display:block;padding:10px;">

        <div class="annytab-form-label">Name</div>
        <div class="annytab-input-group">
            <div class="input-group-cell" style="width:460px;text-align:left;">
                <input name="txtName" type="text" class="input-group-control" value="" placeholder="Marvin Swansson" />
            </div>
            <div class="input-group-cell" style="width:40px;border-left:1px solid #d9d9d9;cursor:help;"
                 title="Enter your name in this textbox." rel="tooltip">
                <i class="far fa-question-circle fa-fw fa-lg"></i>
            </div>
        </div>

        <div class="annytab-form-label">City</div>
        <div class="annytab-input-group">
            <div class="input-group-cell" style="width:460px;text-align:left;">
                <input name="txtCity" type="text" class="input-group-control" value="" placeholder="Stockholm" />
            </div>
            <div class="input-group-cell" style="width:40px;border-left:1px solid #d9d9d9;cursor:help;"
                 title="Enter the name of the city in which you live at the moment." rel="tooltip">
                <i class="far fa-question-circle fa-fw fa-lg"></i>
            </div>
        </div>

        <div class="annytab-form-label">Color</div>
        <div class="annytab-input-group">
            <div class="input-group-cell" style="width:460px;text-align:left;">
                <input name="txtColor" type="text" class="input-group-control" value="" placeholder="Red" />
            </div>
            <div class="input-group-cell" style="width:40px;border-left:1px solid #d9d9d9;cursor:help;"
                 title="Enter the name of your favorite color in this textbox. Your favorite color says a lot about you, it tells us which color you like the most :)." rel="tooltip">
                <i class="far fa-question-circle fa-fw fa-lg"></i>
            </div>
        </div>

    </div>

    @*Scripts*@
    @*<script crossorigin="anonymous" src="https://polyfill.io/v3/polyfill.min.js?features=Element.prototype.closest%2CElement.prototype.remove"></script>*@
    <script src="/js/font-awesome/all.min.js"></script>
    <link href="/css/annytab.tooltip.css" rel="stylesheet" />
    <script src="/js/annytab.tooltip.js"></script>

</body>
</html>

Leave a Reply

Your email address will not be published. Required fields are marked *