# Testing Shadow DOM

> Shadow DOM is a new DOM feature that helps you build components. You can think of shadow DOM as a scoped subtree inside your element.\
> [polymer-project.org](https://polymer-library.polymer-project.org/2.0/docs/devguide/shadow-dom)

Shadow DOM is a technology that unlocks such features as isolated DOM and scoped CSS. It's usually used with custom elements to isolate their DOM from the global one. Puppetry targets are relative to a DOM scope (global or local). In order to query elements inside custom elements we have go with chained targets. So we are to create a target for the host element (the custom element root) and targets for the hosted sub-elements that point to the host target.&#x20;

It's much easier to explain with an example. Imagine we have a custom element foo-component, built out of a template:

```markup
<foo-component id="fooShadowRoot"></foo-component>
<template id="fooTemplate">
  <div id="shadowLocalTarget">
    Local Target in Shadow DOM
  </div>  
</template>
```

We can register the component with following code:

```javascript
document.addEventListener( "DOMContentLoaded", () => {

    function registerCustomElement( elName, templateId ) {
      globalThis.customElements.define( elName, class extends HTMLElement {
      constructor() {
          super();
          this.attachShadow({ mode: "open" });
          this.shadowRoot.appendChild( document.getElementById( templateId ).content );
        }
      });
    }

    registerCustomElement( "foo-component", "fooTemplate" );
});
```

Now if we inspect the page DOM with DevTools we can find the following sub-tree:

![](https://3461068122-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LdyKJ-zzeS2hB7DF04J%2F-LtymvxQS26zwwSTM_qg%2F-LtysXayBOAcNZK1HSNU%2Ffoo-component.png?alt=media\&token=9587c787-75ca-41e2-b736-3e45a67e604d)

Let's say our goal is to access a local target (#shadowLocalTarget), hosted by foo-component element (fooShadowRoot).&#x20;

> With DevTools you can inspect the target element and get with Copy/JS Path code like the that:\
> document.querySelector("#fooShadowRoot").shadowRoot.querySelector("#shadowLocalTarget")\
> If we translate it to Puppetry it actually gives us two targets:\
> \- shadow root:  #fooShadowRoot \
> \- hosted element: #shadowLocalTarget, with the first target for the parent

What we have to do first is to create in Puppetry a target for foo-component (shadow root):

![Defining shadow root target](https://3461068122-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LdyKJ-zzeS2hB7DF04J%2F-LtymvxQS26zwwSTM_qg%2F-Ltyu6zV9plxkktlJqvU%2Fshadow-root.png?alt=media\&token=656e626d-66b7-4193-b9ee-923bb600a3d6)

Then  we create a target for the hosted element

![Defining hosted element target](https://3461068122-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LdyKJ-zzeS2hB7DF04J%2F-LtymvxQS26zwwSTM_qg%2F-LtyuBDltkgSOvUR6SEb%2Fshadow-local.png?alt=media\&token=46b1df84-481f-4ea3-b5cd-c78b55abab09)

The first one is a simple target like we are used to have in Puppetry, but the second is chained one. While building it we expand Options, set **Parent target** to `SHADOW_FOO` and **Parent type** to `shadow host`.

![Chained target](https://3461068122-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LdyKJ-zzeS2hB7DF04J%2F-LtymvxQS26zwwSTM_qg%2F-Ltyuth3vvu4X9qKb4xh%2Fshadow-targets.png?alt=media\&token=2bbc92ef-4afc-477d-a50b-87857ceaf1c8)

As soon as the hosted element target defined (`SHADOWDOM_FOO_LOCAL`) we can address it as any simple target:

![Addressing a chained target](https://3461068122-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LdyKJ-zzeS2hB7DF04J%2F-LtymvxQS26zwwSTM_qg%2F-LtyuylKl8VVEZqJ2aEF%2Fshadow-test.png?alt=media\&token=27901b53-43ff-48f9-9902-63da559a766e)
