javascriptweb-component

How to use querySelector of Tags inside a Web Component


I am building an application with Web Components and only vanila javascript. I want to use vaadin-router for routing.

In my index.html I only display the web component app.module:

<!DOCTYPE html>
    <body>
        <mp-app-root></mp-app-root>
    </body>
</html>

the app module is a simple web component. It should display the routing module in a template. The Shadow DOM is optional.

app.module.js

import Template from './app.module.template.js'

class AppModule extends HTMLElement {
    connectedCallback() {
        this.innerHTML = Template.render();
    }
}

customElements.define('mp-app-root', AppModule)

The template simply renders the tag, where the routing should happen.

app.module.template.js

import './routing.module.js'

export default {
    render() {
        return `${this.html()}`;
    },

    html() {
        return `<script type="module" src="./routing.module.js"></script>
                <app-routing-module></app-routing-module>`;
    },
}

As you can see, i am importing the script routing.module.js - It also works, when im console.logging something

Now, I am using vaadin-router for routing and I want to access the <app-routing-module>-Tag with querySelector like this:

const outlet = document.querySelector('mp-app-root').querySelector('app-routing-module')

but it is always null.

console.log(document.querySelector('mp-app-root') works and prints the following:

<mp-app-root>
    <app-routing-module></app-routing-module>
</mp-app-root>

Solution

  • You get null, you can't access the lightDOM
    Because the connectedCallback fired on the opening tag

    This is considered the correct implementation of the W3C Web Components standard
    (Firefox got it wrong until they fixed it in 2021)

    See:

    working code: (read that long blogpost)

    setTimeout( () => {
      const outlet = document.querySelector('mp-app-root')
                             .querySelector('app-routing-module')
    });
    

    All WebComponent libraries do something similar under the hood;
    delay execution till the Eventloop is empty, and the DOM is ready to accept your selections/additions.


    Note: querySelector takes a selector, so you can write:

      const outlet = document.querySelector('mp-app-root app-routing-module')