How to Get the Contents of a Custom Element

After some research online, I found the following nugget about connectedCallback: each time the custom element is appended into a document-connected element. This will happen each time the node is moved, and may happen before the element's contents have been fully parsed.

Therefore, depending on the browser, innerHTML may not in fact be defined when being used. That's why the above snippet, while fine in Firefox, doesn't work in Chrome or Edge.

To solve this problem, place the script tags at the bottom of the body, in which case the element will be parsed first, and the script will know what innerHTML contains.

Another way around this is to wrap the custom element constructor inside a DOM loaded event. That event would look like so:

document.addEventListener('DOMContentLoaded', (e) => {
   class markDown extends HTMLElement {
      ...
   }
}

Yet another way of doing this is putting your script in a separate file, and marking the script tag with the defer attribute.

All three solutions work whether or not the class is explicitly named and defined by a separate statement, as mentioned by Triby's answer, or anonymous and wrapped by the custom element definition function, as in the original question.


I have been bitten by this so much, I purposely asked a StackOverflow question for people to find

wait for Element Upgrade in connectedCallback: FireFox and Chromium differences

The easiest workaround is a setTimeout in the connectedCallback

<script>
  customElements.define('my-element', class extends HTMLElement {
    connectedCallback() {
      console.log(this.innerHTML);// "A" in FireFox, "" in other Browsers
      setTimeout(() => {
        // now runs asap 
        console.log(this.innerHTML); // "A"
      });
    }
  })
</script>

<my-element>A</my-element>

What this and all mentioned workarounds do is postpone code execution until the DOM is fully parsed.
setTimeout runs after DOMContentLoaded, but if you wrap everything in DOMContentLoaded the whole Element creation runs late, same applies for defer or placing <script> at the end of your page

Supersharp explains the why better in:

wait for Element Upgrade in connectedCallback: FireFox and Chromium differences