1

TLDR: moving the cursor from tooltip back to triggering element closes, shows and closes the tooltip (flickers).

I need to make the tooltips open on hover and make their content clickable. I have found a working example here on SO.

As you hover over the element it shows you a tooltip which can be interacted with, once you move the cursor away from the tooltip it closes.

There is a problem though.

If you leave the tooltip and move the cursor back on the element which triggered the tooltip, the tooltip pops back up, but dissapears after a moment ("flickering"). You need to move the cursor away from the element and back on the element for the tooltip to show again.

What I am trying to do, is check if the cursor is back on the triggering element and if that is the case not run the closing function (tooltip.hide()).

I have tried to do this by imitating the existing process from the example found on SO. That is, check if the tooltip has lost :hover, setTimout (300ms) and check if cursor is now positioned on the triggering element or back on the tooltip.

Here is a jsFiddle example.

This is the code. The problematic code is between the two looong comment lines.

Note: Moving the cursor away from the triggering element and back on the triggering element also triggers the flickering.


//https://stackoverflow.com/questions/67993080/bootstrap-5-make-tooltip-hoverable-and-link-clickable
var tooltipTriggerList = [].slice.call(document.querySelectorAll('button'))
for (let tt of tooltipTriggerList){
    tt.setAttribute("data-bs-placement","top")
}

var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
    const tooltip =  new bootstrap.Tooltip(tooltipTriggerEl, {
        trigger: "manual",
        'customClass': 'custom-tooltip'
    })

    let tooltipElTimeout;
    let currentToolTip;
    
    let currentTooltipTimeout;

    tooltipTriggerEl.addEventListener("mouseenter", function () {
        let toolTipID;
        
        // Clear Set Timeout
        clearTimeout(currentTooltipTimeout);
        
        // Show Tooltip
        tooltip.show();

        
        // Assign current tooltip ID to toolTipID variable
        toolTipID = tooltipTriggerEl.getAttribute("aria-describedby");

        
        // Assign current tooltip to currentToolTip variable
        currentToolTip = document.querySelector(`#${toolTipID}`);

        /*******************************************************************/
        // Hide tooltip on tooltip mouse leave
        currentToolTip.addEventListener("mouseleave", function () {
            currentTooltipTimeout = setTimeout(()=>{
                    console.log("!currentToolTip.matches(':hover')");
                    console.log(!currentToolTip.matches(":hover"));
                    if(!tooltipTriggerEl.matches(":hover")){
                        console.log("!tooltipTriggerEl.matches(':hover')");
                        console.log(!tooltipTriggerEl.matches(":hover"));
                        if (!currentToolTip.matches(":hover")) {
                            tooltip.hide();
                        }
                    }
            }, 300)
        });
  
    /***********************************************************************/

    });

    tooltipTriggerEl.addEventListener("mouseleave", function () {
      // SetTimeout before tooltip disappears
      tooltipTimeout = setTimeout(function () {
        // Hide tooltip if not hovered.
        if (!currentToolTip.matches(":hover")) {
          tooltip.hide();
        }
      }, 100);
    });

    return tooltip;

})

Thank you

Edit: Amine Ramouls answer is correct. isHidden also needs to bet set to false on the 2cnd eventListener, otherwise the tooltips no longer work (problem with aria-describedby).

WeAreDoomed
  • 248
  • 1
  • 14

1 Answers1

2

in your code you have an event listener wich add an event listner and that's a big mistake because it add an infinit number of eveneent listner to your element.

so you juste have to organize your code like this :

//https://stackoverflow.com/questions/67993080/bootstrap-5-make-tooltip-hoverable-and-link-clickable
var tooltipTriggerList = [].slice.call(document.querySelectorAll('button'))
for (let tt of tooltipTriggerList){
    tt.setAttribute("data-bs-placement","top")
}

var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
    const tooltip =  new bootstrap.Tooltip(tooltipTriggerEl, {
        trigger: "manual",
        'customClass': 'custom-tooltip'
    })
    let isHidden = true;        
    let currentTooltipTimeout;
    tooltipTriggerEl.addEventListener("mouseenter", function () {

        let toolTipID;
        // Clear Set Timeout
        clearTimeout(tooltipElTimeout);
        clearTimeout(currentTooltipTimeout);
        
        if (isHidden)
        {
                tooltip.show();
            isHidden=false;
        }
            
        
    });
        // Hide tooltip on tooltip mouse leave
    tooltipTriggerEl.addEventListener("mouseleave", function () {
                                           
                    console.log("!currentToolTip.matches(':hover')");
                    if(!tooltipTriggerEl.matches(":hover")){
                            currentTooltipTimeout=setTimeout(()=>{
                            if (!isHidden && !tooltipTriggerEl.matches(":hover")){
                                tooltip.hide();
                              isHidden=true;
                          }
                            
                            console.log("!tooltipTriggerEl.matches(':hover')");
                            console.log(!tooltipTriggerEl.matches(":hover"));
                        }, 3000)
                    }                
        });
  
    return tooltip;

})

now as you can see i juste added the isHidden var to check if the popup info is hidden or not, you can do that with the element if you can get it by a query selector request. that's it. enjoy your life.

Edit: i forget to tell you that i have put 3 seconde before checking the if the popup is hidden or not.

Amine Ramoul
  • 136
  • 10
  • I've actually found a problem with the code. Once the tooltip is closed, it doesn't open again. I get an error `currentToolTip is null` in a try catch block. You can see the problem here https://jsfiddle.net/v4au9tsm/3/ – WeAreDoomed Dec 16 '22 at 17:13
  • I've narrowed it down to `aria-describedby`, as the 2cnd time it isn't generated – WeAreDoomed Dec 16 '22 at 17:34
  • i have checked your code in https://jsfiddle.net/v4au9tsm/3/ => you can't nest events, that's it i already explain it to you . – Amine Ramoul Dec 17 '22 at 17:26
  • for the error that you mentioned in the previous comment, the error result from you have moved the declaration if isHidden in an event so the second evenet can't access to this var and you got the error – Amine Ramoul Dec 17 '22 at 17:28
  • you can check the fix of https://jsfiddle.net/v4au9tsm/3/ here https://jsfiddle.net/yf30cxnh/ – Amine Ramoul Dec 17 '22 at 17:37