How to query elements within shadow DOM from outside in Dart?
For people wanting an easy to use solution
function $$$(selector, rootNode=document.body) {
const arr = []
const traverser = node => {
// 1. decline all nodes that are not elements
if(node.nodeType !== Node.ELEMENT_NODE) {
return
}
// 2. add the node to the array, if it matches the selector
if(node.matches(selector)) {
arr.push(node)
}
// 3. loop through the children
const children = node.children
if (children.length) {
for(const child of children) {
traverser(child)
}
}
// 4. check for shadow DOM, and loop through it's children
const shadowRoot = node.shadowRoot
if (shadowRoot) {
const shadowChildren = shadowRoot.children
for(const shadowChild of shadowChildren) {
traverser(shadowChild)
}
}
}
traverser(rootNode)
return arr
}
Use it like this:
var nodes = $$$('#some .selector')
// use from a custom rootNode
var buttonsWithinFirstNode = $$$('button', nodes[0])
It will traverse all the elements within the rootNode, so it won't be fast but it is easy to use.
Update2 (from comments)
If you use a custom main, ensure that Polymer is properly initialized before you try to interact with your Polymer elements (see how to implement a main function in polymer apps for more details).
I usually suggest to avoid a custom main and create an app-element
(or whatever name you prefer) and put your initialization code into attached
(ensure to call super.attached();
) or in ready()
(doesn't need the super call).
Original
It seems in this case it's not in the shadow DOM but a child.
This should work:
querySelector('h2');
It's only in the shadow DOM when it is within your elements <template>...</template>
not when you wrap it in the tag of your custom element.
<polymer-element name="some-element">
<template>
<!-- this becomes the shadow DOM -->
<content>
<!--
what gets captureD by the content element becomes a child or some-element
-->
</content>
</template>
</polymer-element>
<body>
<some-element>
<!-- these elements here are captured by the
content tag and become children of some-element -->
<div>some text</div>
</some-element>
</body>
Update
If you want to search
inside the shadow DOM of the current element
shadowRoot.querySelect('h2');
inside the shadow DOM of an element inside the shadow DOM
shadowRoot.querySelector('* /deep/ h2');
shadowRoot.querySelector('ui-button::shadow h2');
from outside the current element
import 'dart:html' as dom;
...
dom.querySelector('* /deep/ h2');
// or (only in the shadow DOM of <app-element>)
dom.querySelector('app-element::shadow h2');
dom.querySelector('app-element::shadow ui-button::shadow h2');
// or (arbitrary depth)
dom.querySelector('app-element /deep/ h2');
Pseudo selector ::shadow
and combinator /deep/
doesn't work on firefox.
Use .shadowRoot
var shadowroot = app-element.shadowRoot;
shadowroot.querySelector('h2');