0

I try to get a html custom element to work:

When viewing the following example in the browser I must conclude that this.dataset.text attribute in the constructor() is:

  • present before the script defining the custom element
  • empty after the script defining the custom element

<html>
    <head>
        <title>myimage</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
    </head>
    <body>
        <div>
        before custom element definition: <my-element data-text="Replaced and works as expected">Not Replaced</my-element>
        </div>
        <script>
          class MyElement extends HTMLElement {
            constructor() {
              super();
              this.text_attribute= this.dataset.text;
            }

            connectedCallback() {
              if (this.text_attribute) {
                this.innerText = this.text_attribute;
              }
            }
          }
          customElements.define('my-element', MyElement);
        </script>
        <div>
        after custom element definition: <my-element data-text="Replaced">Not Replaced</my-element>
        </div>
    </body>
</html>

This seems to be a common behavior in chrome and Firefox. I can provide some more facts:

  • the this.dataset.text is always present in connectedCallback()
  • accessing the text-attribut via this.getAttribute('data-text') does behave in the same way as above

Can anyone explain the purpose of this seemingly buggy behavior?

0

1 Answer 1

1

This isn't buggy behavior.

Your first <my-element> is processed by the DOM parser before you define it.
Thus all attributes are known (in the DOM) when the constructor executes.

In general you don't access DOM in the constructor; as it also runs when you do:

 let foo = document.createElement("my-element"); // absolutly no DOM created

Here is a trimmed down example:

<style>
  my-element { display:block }
</style>
<my-element id="FOO"> ONE </my-element>
<script>
  customElements.define('my-element', class extends HTMLElement {
    constructor() {
      super();
      document.body.append(` ► constructor id:${this.id} ◄ `);
    }
    connectedCallback() {
      document.body.append(` ► connected id:${this.id} ◄ `);
    }
  });
</script>
<my-element id="BAR"> TWO </my-element>
<my-element id="BAZ"> THREE </my-element>

NOTE

  • How FOO innerHTML is written (because it was parsed) to the DOM before its constructor runs

  • How BAR and BAZ constructor run before its innerHTML is written to the DOM
    and the id value doesn't exist yet

  • I have seen many courses where they "save" you from this standard behavior by executing the <script> async, thus after all DOM is parsed. They don't understand the technology...

Sign up to request clarification or add additional context in comments.

4 Comments

Thanks for the explanation. I just add a helpful link to the spec. html.spec.whatwg.org/multipage/….
Good link, alas official documentation can be wrong. The part "super() must be the first statement" is wrong. See my post: dev.to/dannyengelman/…
What is wrong about loading the script async. The constraints in the spec are not ensured. but your answer points out that this "solution" is not clean. Can you give an impression why loading async does not solve the problem?
No I am not saying it does NOT solve the problem. I am saying it is the blunt way to solve the problem. "Hey, we do not understand why we can't load script early anymore; you know what, we just make sure it never loads early" <enter-FOUCs> Consider Icons or anything above the fold UI, you want it all to show ASAP, not having to wait for the upgrade.. because you whacked on async. Ergo: you do not understand how the technology works. But hey.. I see Lit gurus promoting async to solve this issue.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.