6

I am building a tool that utilizes d3.js for data visualization. The tool relies on webcomponentss and the shadowDOM. d3.js is not able to select any nodes in the shadowDOM just by d3.select. Is there a way to get d3 working inside shadowdom or am I missing something obvious?

In detail:

d3.select("#insideShadowDom")

does not return / select anything provided you have something like

<web-component>
#document-fragment
   <div id="insideShadowDom"></div>
</web-component>

To clarify: The shadowDOM is generated by a framework. I found a way to get the initial shadowRoot (injected). However I'm still wondering if it is possible to tell d3 about the shadowDOM even though I don't have the handle that createShadowRoot() returns.

0xcaff
  • 13,085
  • 5
  • 47
  • 55
ins0m
  • 850
  • 10
  • 20
  • Could you post an example please? I don't have any experience with shadow DOM but in principle you should be able to use D3 with it as far as I can tell. – Lars Kotthoff Dec 13 '13 at 09:33
  • If I understand correctly, you can't cross DOM boundaries, i.e. the thing you select from has to be in the right DOM. So code like `elementInShadowDom.select("#insideShadowDom")` should work. – Lars Kotthoff Dec 13 '13 at 14:55
  • i am calling select on the d3 root object and it certainly does not return anything, but I'll check again. You suggest to call select on a dom element itself ? – ins0m Dec 13 '13 at 14:59
  • Yes -- so something like `var foo = d3.select("...").append("..."); foo.select("...")`. – Lars Kotthoff Dec 13 '13 at 19:44
  • No, that doesn't open the shadowDOM for d3 – ins0m Dec 13 '13 at 19:55
  • Could you post an example that demonstrates the problem please? – Lars Kotthoff Dec 13 '13 at 20:04
  • i added a shadow-dom example. – ins0m Dec 13 '13 at 20:20
  • [This example](http://jsfiddle.net/j3p3d/) works fine for me (in Chrome). Note that the second selector doesn't select anything as it would cross DOMs, but the third works fine. – Lars Kotthoff Dec 13 '13 at 20:42
  • Of course that works. You create the shadowDom by yourself and have a handle. I dont. – ins0m Dec 13 '13 at 20:59
  • Well, your example works fine for me -- http://jsfiddle.net/XNVr3/ – Lars Kotthoff Dec 13 '13 at 21:45
  • yes, because once a shadowDOM is created this is not the markup that you can see in the code. the #document-fragement is just a marker to show you the code of the shadwDOM itself (generated by chrome). However, this is not what is actually in the DOM. In your example you could access this element only because you had a handle to it. The difference is that i want to access a shadowDOM that another script generates. Imagine your first example and trya to get the shadowDOM without having the handle that "createShadowDom" gives you. – ins0m Dec 14 '13 at 01:36
  • You can do this by selecting `.webkitShadowRoot` (in Chrome) of the element that contains the shadow DOM -- http://jsfiddle.net/j3p3d/1/ – Lars Kotthoff Dec 14 '13 at 10:08
  • Aaaaah, i did not stumble upon this call. Write this down as an answer and I'll gladly mark it as correct – ins0m Dec 14 '13 at 13:34

3 Answers3

5

You can pass in object -- also, use var if you need to reference the object from a callback:

<polymer-element name="my-element">
    <template>
        <div id="foobar"></div>
    </template>
    <script>
        Polymer('my-element', {
            ready: function() {
                var foobar = this.$.foobar;
                someCallback(function() {
                    d3.select(foobar).
                    ...
                }); 
                ...
            }
        });
    </script>
</polymer-element>
Juhani
  • 59
  • 1
  • 2
3

While DOM selectors won't work across DOMs, you can get access to a shadow root (at least in Chrome) through the .webkitShadowRoot property. Passing this to d3.select(), you can then select any elements in the shadow DOM as usual.

Demo here.

Lars Kotthoff
  • 107,425
  • 16
  • 204
  • 204
-1

I know this is old, however, with the latest Polymer version (1.0.0) you can access shadow dom elements with:

<template> ... <div id="elementId"></div> ... </template>


Polymer({
    ready: function() { var svg = d3.select(this.$.elementId).append('svg'; }
});

This will allow you to render the chart and appropriately select the shadow dom element.

Michael
  • 891
  • 2
  • 16
  • 32