Tippyjs: Unable to use the same HTML template for multiple tooltips

Created on 14 Sep 2017  路  9Comments  路  Source: atomiks/tippyjs

Hello,

I have an issue, where I'm unable to use the same HTML template for multiple tooltips.

Here's my init code:

var poppers = Array.from(document.querySelectorAll('[data-toggle="popper"]'));
tippy(poppers, {
    position: 'bottom',
    trigger: 'click',
    duration: 100,
    interactive: true,
    arrow: true,
    performance: true,
    html: document.querySelector('.popper')
});

Only the last [data-toggle="popper"] is able to toggle the tooltip, the first ones just display an empty box.

Any ideas how to fix this? :) Popper.js and tippy.js are looking very awesome!

Most helpful comment

Alright, I've simplified the hell out of the Creating HTML Templates section. That was really wordy and hard to read before. Now I've simplified it and explicitly noted the two options.

https://atomiks.github.io/tippyjs/#creating-html-templates

All 9 comments

I kind of stumbled upon this and debugged this the hard way just a few weeks ago (new to using tippy.js by maybe about a month now). I was going to suggest a fix for it but there's a workaround: use Node.cloneNode(true).

It's not written in the docs, but the template you're referring to ('.popper') is being taken away from the DOM. Check it out in your project.

@atomiks the long term fix is to either handle the cloning of the node internally or update the docs to describe this behavior.

Hope this helps @raineluntta.

Templates are cloned when you use a selector ID string like '#template' instead of using the Element directly. Otherwise the workaround is cloneNode as @padi said

@atomiks Ah yes, using the id does clone the element, but I was kind of expecting a document.querySelector('...') to do the same for consistency (one html option does destructive behavior while the other doesn't).

The Element option was added because cloning doesn't keep event listeners attached which someone needed. So you've got the option of using the Element directly or cloning it. String = clone, Element = direct append.

I mentioned that in the docs but maybe it wasn't explained too well... probably need to overhaul the wording on everything for v2

@atomiks I see. One of the reasons why I didn't say this before was because I wanted (2) others on my team to use tippy and see how they would use it. The behavior I described is one of the few common stumbling blocks we had (i.e. they also didn't expect the template to be gone).

A cleaner workaround to keeping the event listeners attached is to use event delegation. For example, if you have appendTo: document.body, you could do something like

<body>
  <!-- other content -->

  <!-- content below is not immediately here until `.show(popper)` is used -->
  <span class='.btn-inside-tippy'>I'm inside Tippy!</span>
</body>
// You can also do something similar in pure javascript
jQuery("body").on("click", ".btn-inside-tippy", function() {
  var targetElement = $(this);
  targetElement.doSomething();
});

Or if you're concerned about performance of attaching listeners to the body, have something else for appendTo:

<body>
  <!-- other content -->
  <div id=tippytemplates-container>
    <!-- content below is not immediately here until `.show(popper)` is used -->
    <span class='.btn-inside-tippy'>I'm inside Tippy!</span>
  </div>
</body>
jQuery("#tippytemplates-container").on("click", ".btn-inside-tippy", function() {
  var targetElement = $(this);
  targetElement.doSomething();
});

This is how turbolinks gets around replacing the tag in between turbolinks:page_loads. There's a few other known techniques such as making use of MutationObserver, but for me event delegation is good enough to pick up by everyone without much effort.

I guess that depends on how the developer is using it and can't be controlled by the library... so I guess the solution is a better explanation in the docs?

@atomiks This is mostly up to you. You have 2 options:

  1. Handle cloneNode(true) inside the library when an Element/Node is passed and make an explicit advice about using event delegation. This is to be added in v2 of tippy.js anyway, so you can introduce breaking changes (developers will have to alter their event bindings).

Pros:

  • The same html tippy setting does the same behavior for the 2 kinds of parameters/options. The html template is copied over they are templates, and switching your tippy options between id and Element should require no further changes in other parts of your js code, since...
  • You can keep your listeners for both the id or the Element option if you use event delegation.

Cons:

  • I don't know if this is easy to implement or how much this can impact performance.
  • This requires the user to move away for directly adding event listeners on the template. But this probably given in v2 as well.
  1. Using Node.clodeNode(true) and event delegation should be part of an explicit example. Make sure that the user expectations are not broken by hinting at the different behavior between using and id and an Element. More importantly, make it explicit* that the original template is taken away from the DOM.

Pros:

  • The change does not involve a change in the codebase, just the docs.

Cons:

  • The change involves organizing the docs such that this slight change of behavior between different options (id, Element) of the same setting screams at the user.

Personally, I'm slightly leaning towards 1.


Off topic:

Related comment about the docs: As it currently stands, it has a very great "above the fold" content, but the dense text below is just difficult to skim for the behavior a user wants. This is probably part of why every tippy user I've seen so far has missed this quirk. A quick solution would be to have a sidebar that links to each section of the static website.

You can email me at [email protected] to continue the discussion so that we can avoid littering this issue with unrelated content.

Alright, I've simplified the hell out of the Creating HTML Templates section. That was really wordy and hard to read before. Now I've simplified it and explicitly noted the two options.

https://atomiks.github.io/tippyjs/#creating-html-templates

Great discussion here! Thank you for the solution, I honestly read the documentation multiple times but couldn't see that I could use the ID selector for my purpose. Glad the documentation is clearer now! :)

Was this page helpful?
0 / 5 - 0 ratings

Related issues

kmanolis picture kmanolis  路  4Comments

andrewckor picture andrewckor  路  4Comments

patrickhlauke picture patrickhlauke  路  3Comments

Neill83 picture Neill83  路  3Comments

divmgl picture divmgl  路  3Comments