22

I defined a component with polymer like this:

<polymer-element name="my-component">
  <template>
    <div id='test'>CONTENT</div>
  </template>
</polymer-element>

Now I want to access the shadow dom, for example: to get the content of div id='test'

var x = $("div#test").html();

The given code doesn't work. Can I access the shadow dom with jquery?

David Smith
  • 38,044
  • 11
  • 44
  • 61
mica
  • 3,898
  • 4
  • 34
  • 62

10 Answers10

21

No, not outside of the Polymer element.

After reading up on Polymer, it looks like you can only have access to the shadow-DOM of Polymer elements in scripts within the Polymer element. The Polymer docs on Automatic node finding say:

Every node in a component’s shadow DOM that is tagged with an id attribute is automatically referenced in the component’s this.$ hash.

This means you can add a <script> tag as a sibling to <template> where this.$.test will be the element you want.

<polymer-element name="my-component">
  <template>
    <div id='test'>CONTENT</div>
  </template>
  <script>
    Polymer('my-component', {
        logNameValue: function () {
            console.log('polymer element', this.$.test);
            console.log('jQuery wrapper of polymer element', $(this.$.test));
        }
    });
  </script>
</polymer-element>
Cory House
  • 14,235
  • 13
  • 70
  • 87
Henry Blyth
  • 1,700
  • 1
  • 15
  • 23
11

You can use $('body /deep/ your-selector') pattern to pierce through shadow DOM and get Jquery to work inside it.

update: So far I have only managed to make this work on chrome for desktop. I believe, other browsers do not support the /deep/ combinator.

update 2: /deep/ combinator is deprecated and should not be used anymore. It is scheduled to be removed from Chrome.

David Aroesti
  • 596
  • 4
  • 10
6

I'm able to access the shadowRoot elements in Chrome like so:

$("#idOfElementInShadowRoot", $("#idOfShadowRootElement").shadowRoot)

Got the idea from Jquery: How to select only within a selection?

user11302188
  • 73
  • 1
  • 4
  • 1
    You will need a `[0]` after `$("#idOfShadowRootElement")`, because `.shadowRoot` is on DOM objects but not on jQuery ones. So like this: `$("#idOfElementInShadowRoot", $("#idOfShadowRootElement")[0].shadowRoot)` – DawnPaladin Feb 25 '21 at 20:41
  • Have to be using the "open" mode of `attachShadow` for this to work. "closed" mode will give you null. Otherwise a great answer, thanks! – Victor Zakharov Jul 26 '21 at 17:41
3

I think this works for me...

$('polymer-element::shadow #test')

Only tested it on chrome though

Val
  • 17,336
  • 23
  • 95
  • 144
  • 3
    This is also deprecated. https://stackoverflow.com/questions/35741722/whats-the-substitute-for-shadow-and-deep – Ally Jun 12 '17 at 02:55
2

You can do it like this:

$("#example", this.shadowRoot).DataTable();
Benedikt J Schlegel
  • 1,707
  • 1
  • 10
  • 23
2

This worked for me

$(element)[0].shadowRoot

IMPLATRIX
  • 21
  • 2
1

I wrote simple helper in TypeScript to solve this problem:

class DomUtils {

    public static getShadowElementById(id: string):any {

        try {
            // Try to get it by simple id in case of browser doesn't support shadow DOM
            var element = $("#" + id);

            if (element.length <= 0) {
                // Support Chrome browser
                element = $("body /deep/ #" + id);
            }

            return element;

        } catch (error) {
            console.log("Error: " + error + ", while trying to get shadow element with id: " + id);
            return null;
        }
    }
} 

Usage:

var element = DomUtils.getShadowElementById('mainContainer');

Tested on desktop Chrome, Internet Explorer, Firefox

Konrad G
  • 419
  • 7
  • 14
1

Use something like this:

jQuery.fn.extend({
  shadowRoot: function() {
     return $(this.get(0).shadowRoot);
  },
});

and call:

$("my-element").shadowRoot());
Peter Karena
  • 71
  • 1
  • 1
0

this is my simple function to change capcha in shadow-root

const get_captcha = (CustomElement)=>{
 var src = `./app/create_captcha/${chance.natural()}`;
 var rootElement = $(CustomElement)[0].shadowRoot;
 var captchaElement = $(rootElement).find('#img_captcha');
 $(captchaElement).attr('src',src);
};
0

For what it's worth tossing this into the list of answers since it's ultimately what I used.

// following line assumes shadow content has only one <body> tag... 
// ...otherwise filter by whatever makes sense for your code

var $shadowBody = $($("#shadow-root-elem")[0].shadowRoot.childNodes).filter("body");

// get the elem in the shadow content that I need/want

var $elemInShadowBody = $shadowBody.find(".selector.for.elem.in.shadow.body")
Art Geigel
  • 1,915
  • 3
  • 22
  • 24