polymerweb-componentshadow-dompwa-starter-kit

Expose web-component element from ShadowDom to external JS using document.getElementById


I am working with the current PWA starter kit template from Polymer.

https://github.com/Polymer/pwa-starter-kit/tree/template-typescript

My web-component element page return the following code with a DIV element:

return html`
      ${SharedStyles}    
      <section>
        ...my content...

      </section>
      <div id="CONTAINER NAME"></div>
    `

I need to get access to the CONTAINER NAME element from an external javascript via document.getElementById. I know that it sit's in the shadow dom but I cant change the external JS. So question is how to make it accessible from JS via document.getElementById?

The external JavaScript loads an iframe into the named div. This external component needs to get the div element by document.getElementById to load the iframe into the specified div.

I have searched and haven't found a way to force the div element from the shadow dom of my web-component page to be exposed/placed in the DOM.

I just found this solution mentioned here but I didnt get it to work in the PWA template. Maybe as the shadow doms are cascaded in the PWA template?

https://stackoverflow.com/a/47082470/9192527

Is there any way I can update the web component based on the Polymer v3/PWA kit with the external javascript (third party) still using document.getElementbyId to modify my div inside the web component?

So looking for a possibility using maybe slots to expose an element of the shadow dom to the light dom? But cant get it to work with the solutions linked above.


Solution

  • As you mentioned, lit-element uses shadow dom by default as it has a lot of advantages when you're making reusable components.

    However, you can opt out of it and use "light" dom which will render the component's content in the main dom which in turn will make that content accessible using things like document.getElementById() or document.querySelector()

    Here's a minimum example of how to do use light dom in a lit-element-based component (and here's a glitch where you can see it in action)

    class MyElement extends LitElement {  
      render() {
        return html`
          <section>
            ... My content ...
          </section>
          <div id="myElementContainer">
            This is a container inside my element
          </div>
        `;
      }
    
      createRenderRoot() {
        // this is what overrides lit-element's behavior so that the contents don't render in shadow dom
        return this;
      }
    
    }
    

    Just bear in mind that in this case you should only use this component once in your application because of how getElementById() works and that you won't be able to use <slot> in your component as that's a feature only available for shadow dom