4

I am trying to do something very similar (if not the same) to what's been asked in the question here (the answer didn't work for me, it seems like the answerer/creator didn't understand the question).

My goal is to have two tippy tooltip instances on a single html element with different trigger options:

  • one which will be triggered on mouseenter event (the default one, created using default tippy constructor without using the trigger option at all), and
  • one which will be triggered on click event (using trigger option manual and calling the tippy show() function afterwards).

This is how I did it:

    var myelement = document.getElementById('myelementid');

    // Default way of creating tippy tooltips
    tippy(myelement, {
        content: 'Shown on hover.'
    });

    // Creating a tooltip which will be triggered manually/programmatically
    var mytippy = tippy(myelement, {
        content: 'Shown on click.',
        trigger: 'manual'
    });

    myelement.addEventListener("click", function() {
        mytippy.show(300);
        setTimeout(function(){ mytippy.hide(300); }, 1500);
    });

And for some reason it won't show the manually triggered tooltip on that element at all. I get this exception: Uncaught TypeError: Cannot read property 'show' of undefined at HTMLImageElement.<anonymous> (refers to the tippy show() function). But when I delete one of them (tippy instances), the other one works perfectly.

Emir
  • 380
  • 3
  • 11

2 Answers2

2

It looks like Tippy.js uses an HTML attribute on elements for the tooltip (i.e., title or data-tippy). Since duplicate attributes would be invalid markup, a workaround might be to change the tooltip text when the element is clicked. Then, after the user moves away from the element, you could change the tooltip text back.

For example:

let myelement = document.getElementById('myelementid');
let to;

let text = "Show on hover."
let tip = tippy(myelement, {
  content: text
});

myelement.addEventListener("click", handleClick);
myelement.addEventListener("mouseout", moveOut);

function moveOut () {
    // when the user moves their mouse away from the button
    // cancel showing the alternate tooltip text
    clearTimeout(to);
    // slight delay to prevent "flash" of original tooltip text
    setTimeout(function () {
        // set the tooltip text back to the original
        tip.setContent(text);
    }, 200);
}

function handleClick () {
    tip.setContent("Click");
    tip.show(300);
    to = setTimeout(function() {
        tip.hide(300);
    }, 1500); 
}

Here's a fiddle demonstrating this: https://jsfiddle.net/g6odqukr/

JoshG
  • 6,472
  • 2
  • 38
  • 61
  • Very nice idea/workaround. It does require an additional event listener but it works exactly as expected. BTW: It seems like this version of Tippy.js does not use title element for showing dynamic tooltips. Instead, it uses an attribute aria-describedby="tippy-1" and creates a new temporary div with id="tippy-1" at the end of body tag. – Emir Aug 28 '19 at 08:07
  • @EmirG. Thank you! I updated the answer to make note of that. – JoshG Aug 28 '19 at 08:37
2

In the meantime I've came to an idea to put one tippy tooltip on the element myelement itself and another one on its parentNode element, and at the moment it appears to be the most simple solution (to understand and to write). It is simple as writing two totaly different tooltips. It requires that the parentNode element has the same size as the myelement itself for it to look like the tooltip actually belongs to the same element.

Here the code:

var myelement = document.getElementById('myelementid');

// Default way of creating tippy tooltips
tippy(myelement, {
    content: 'Shown on hover.'
});

// Creating a tooltip which will be triggered on click
tippy(myelement.parentNode, {
    content: 'Shown on click.',
    trigger: 'click'
});

Here a little bit more advanced version: https://jsfiddle.net/zbhf48gn/

Emir
  • 380
  • 3
  • 11