Popper-core: Support for ShadowDOM and transforms

Created on 20 Sep 2018  路  12Comments  路  Source: popperjs/popper-core

I'm using Tippy, and find it doesn't work with shadow roots or inside transformed elements (two main web techs that I use).

See the codepens in these issues:

Any ideas if the problem is in Tippy, or in Popper?

Most helpful comment

Are there any updates on this ? Happy to help look into an implementation that fixes the issue for all - ShadowDOM is starting to be used by a lot of people and would be a great addition to this library :)

All 12 comments

Looks like the transform issue is in Popper.js. Here's an equivalent using Tooltip.js showing the sane transform issue (codepen).

As for ShadowDOM with Tooltip.js, it seems to half work (codepen). You'll see the tooltip doesn't not hide when you move the mouse away. So I'm not entirely sure it's the same issue, but it might be.

Here's an idea to solve the transformed-container issue. We need to do something along the lines of the following (assuming the element that has the tooltip fixed onto it is itself not transformed):

  • Find the containing block of the element on which we're fixing the tooltip to, as if said element has position: absolute (even if it doesn't have absolute position).

    • Note it doesn't list the fact there that any CSS transformed element establishes a new containing block.

  • Append the tooltip to this containing block.
  • Give the tooltip position: absolute so that it will be positioned relative to the containing block we found.
  • If we're moving the tooltip based on mouse position, we need to map from screen space to the coordinate space of the containing block (how to do this is not described here)
  • If we're placing the tooltip based on the target element's position, we need to find its position relative to that containing block

    • If the target element is itself not transformed, this should be a matter of traversing upward until we reach the containing block, adding up the top/left/padding/margin values along the way.

That's roughly the idea (maybe not completely correct), but paints the general direction. It may be a matter of perusing these search results then figuring which DOM APIs to use.

react-lightweight-tooltip does a super simple technique of wrapping the target element in a position: relative container (making a containing block) then adding the tooltip to there. It works with transforms on the container of the demo. However it has many downsides like it will break absolutely position target elements, and won't work with SVG elements, and more.

Hint.css does a simple technique of using :before/:after CSS content with no JavaScript. It works with transforms, but the content of the tooltips is limited, and doesn't work with SVG, etc.


As for the ShadowDOM issue, I've no idea what's going on there yet.

Hi, please may you provide a codesandbox/codepen example?

Annoying problem :/ Propably everyone who is using framework Polymer v3 will have problem with this.. I tried to debug some code, but I didn't find anything usefull. All boundaries are set correctly, but event onCreate is not called. Creating an online repo is not a piece of cake since I didn't find any CDN for polymer 3

We're investigating on our end too as we need this use case as well. Will report back if we find anything

So we use ShadowDOM VERY heavily with our internal CMS, and ran into this issue. I was able to resolve the tooltips not disappearing properly on mouseout/mouseleave when in a shadowRoot by just binding a custom event listener for it and calling the hide function, like so:

let tip = new Tooltip(tipElement);
tipEl.addEventListener('mouseleave', (_event) => {
  tip.hide();
});

I used mouseleave, but I think that or mouseout both work totally fine depending on your use-case. (Refer to https://developer.mozilla.org/en-US/docs/Web/Events to make your decision there).

I'm not sure why this doesn't just work out-of-the-box, but the fix seems fairly simple. Does anyone see any reason why this might cause some sort of performance hit or anything?

OK, here I am providing examples of tooltip.js not working in ShadowDOM. Note that I also pointed out it appears to not work properly in iFrames as well, so you may wish to take what I have here and dump it into a raw test page.

https://codepen.io/cardtable/pen/GeYxyY

@FezVrasta any thoughts?

I'm fine with writing my own workarounds for ShadowDOM, but I need a way of dealing with it going out of bounds, which I haven't been able to figure out yet.

So I WAS able to fix this by setting the boundariesElement to the body. I'm just always setting it to document.body now.

NOTE: Overall, the logic I implemented to get this working ended up being fairly complicated... if anyone wants details on everything I did I'd be happy to provide examples :)

positioning also doesn't work properly, when using shadowDOM.the root cause here is document.querySelector(options.container) doesn't find anything if container is inside shadow-root. So can we provide the one more api(configurable option) to expilicitly priovide HTMLElement for the container element similarly like arrowElement and boundariesElement.

options.containerElement -> HTMLElement,

Are there any updates on this ? Happy to help look into an implementation that fixes the issue for all - ShadowDOM is starting to be used by a lot of people and would be a great addition to this library :)

positioning also doesn't work properly, when using shadowDOM.the root cause here is document.querySelector(options.container) doesn't find anything if container is inside shadow-root. So can we provide the one more api(configurable option) to expilicitly priovide HTMLElement for the container element similarly like arrowElement and boundariesElement.

options.containerElement -> HTMLElement,

@balajiram you can give dom object to options.container

As of today, positioning seems to work in both the codepens provided here.

Tooltip.js is deprecated, so the mouseleave issue is irrelevant.

Was this page helpful?
0 / 5 - 0 ratings