DEV Community

Cover image for Web-Components #102 - 5 more lessons after learning Web Components #101
Danny Engelman
Danny Engelman

Posted on • Edited on

Web-Components #102 - 5 more lessons after learning Web Components #101

Standing on the shoulders of giants

I learned as much as I could on Web Components development since 2016. And I am still learning.

Credit where credit is due!

I could not have gotten this far without the answers on StackOverflow, the discussions on GitHub and the blogs from early-adoptersยน.

ยน) Old blogs can refer to V0 Web Component technologies not available in the current V1 standard


5 lessons to make your Web Component code better

  • Most (early) examples showed all three Web Component technologies in one code example

    • templates
    • shadowDOM
    • custom Elements API

Each can be used without the other:

  • ๐Ÿ“ You can use templates for any block of inert HTML

  • ๐Ÿ“ You can assign shadowDOM to regular HTML Elements

  • ๐Ÿ“ You can create Custom Elements without templates or shadowDOM


๐Ÿฆ„ 1. <template>

  • creates inert HTML snippets, where previously you would have used:
  <script type="application/html">...</script>
    or
  <div style="display:none">...</div>
Enter fullscreen mode Exit fullscreen mode
  • Templates are parsed when you use template.content.cloneNode(true)

  • If you use template content once, you can skip the .cloneNode(true) part

  • Do not use a <template> just because most (early) blogs show:

  let template = document.createElement("template");
  template.innerHTML = ` CSS & HTML CONTENT `;
  this.shadowRoot.innerHTML = template.innerHTML;
Enter fullscreen mode Exit fullscreen mode

This is a very expensive way of writing:

  this.shadowRoot.innerHTML = ` CSS & HTML CONTENT `;
Enter fullscreen mode Exit fullscreen mode
  • My personal preference, when I do use/need Templates, is to keep <template>s in the <head> of the document.

    • They load early
    • My IDE does all syntax highlighting
    • I use id="UPPERCASE" so they stand out, and the <my-element> can have a generic statement: document.getElementById(this.nodeName) to read the <template>
    
      <template id="MY-ELEMENT">
        <style>
          :host { ... }
        </style>
        <div><slot><slot></div>
      </template>
    
    

    Use this.localeName for lowercase notation id="my-element"

Declarative shadowDOM

templates can create shadowDOM, without the need for JavaScript

<my-element>
  <template shadowrootmode="open">
    <!-- shadowDOM content -->
  </template>
  <!-- lightDOM content -->
</my-element>
Enter fullscreen mode Exit fullscreen mode

๐Ÿฆ„ 2. super()

  • super() sets and returns the this scope.
  constructor() {
    super();
    this.title = "Web Components 102";
  }
Enter fullscreen mode Exit fullscreen mode

can be written as:

  constructor() {
    super().title = "Web Components 102";
  }
Enter fullscreen mode Exit fullscreen mode

๐Ÿฆ„ 3. always call super() first in constructor

  constructor() {
    // Always call super first in constructor
    super();
    // Element functionality written in here
  }
Enter fullscreen mode Exit fullscreen mode

What they meant to say was:

  constructor() {
    // You can *not* reference 'this' *before* it is created by super();
    // It is valid to use *any other* JavaScript *before* super()
    const template = () => document.getElementById(this.nodeName);
    super().append( template().content.cloneNode(true) );
  }
Enter fullscreen mode Exit fullscreen mode

โ€ผ๏ธ Note: template() is a function, it is called after super() created the 'this' scope. So this.nodeName works


๐Ÿฆ„ 4. attachShadow

  • attachShadow sets and returns this.shadowRoot

So there is no need to create your own property:

    this.shadow = this.attachShadow({mode:"open"});
Enter fullscreen mode Exit fullscreen mode
  constructor(){
      super();
      this.attachShadow({mode:"open"});
      this.shadowRoot.innerHTML = `...`;
  }
Enter fullscreen mode Exit fullscreen mode

can all be chained:

  constructor(){
      super() // sets AND returns 'this'
        .attachShadow({mode:"open"}) // sets AND returns this.shadowRoot
        .innerHTML = `...`;
  }
Enter fullscreen mode Exit fullscreen mode
  • note: attachShadow({mode:"closed"}) does not set this.shadowRoot; preventing users from accessing your components shadowRoot. You will hardly see closed being used in the wild

๐Ÿฆ„ 5. appendChild vs. append

  • IE11 did not have the el.append(nodes) method; maybe that is why so many developers stick to appendChild

  • el.appendChild(element) - MDN appendChild documentation

    appends one element, and returns the element reference

  • el.append(nodes) - MDN append documentation

    appends all nodes (text nodes & elements), and returns nothing

    append does not parse HTML, like .innerHTML and .insertAdjacentHTML do

  • When you do not need the appendChild return value; you can rewrite:

      super();
      const shadow = this.attachShadow({mode: 'open'});
      this.div = document.createElement('div');
      this.style = document.createElement('style');
      shadow.appendChild(style);
      shadow.appendChild(div);
    

    to:

      super()
          .attachShadow({mode: 'open'})
          .append( 
                  this.div   = document.createElement('div')  ,
                  this.style = document.createElement('style')
                 );
    

๐Ÿฆ„ Make that 6

See: https://dev.to/dannyengelman/web-component-developers-do-not-connect-with-the-connectedcallback-yet-4jo7

๐Ÿฆ„ Or 7

#103 Dear Web Component





Thank your for reading:

Web-Components #102 - 5 more lessons after learning Web Components #101

Top comments (4)

Collapse
 
hasanhaja profile image
Hasan Ali

Thank you for creating such a great resource!

Templates are parsed when you use template.content.cloneNode(true)

I didn't know this ๐Ÿคฏ

My personal preference, when I do use/need Templates, is to keep s in the of the document.

This is an interesting approach I've not seen or considered before. What are your thoughts on declarative shadow DOM?

Collapse
 
dannyengelman profile image
Danny Engelman • Edited

DSD is a hype until all those developers(*) who whined about it for years start using it now it is available:

source: web-components-usage-metrics.githu...

(*) most doing SSR/SSG for the first time in their lives, because they never learned about the SSR Internet-world pre-WWW in the early 90s (with technologies like Gopher) and the main reason the WWW got popular is because doing things front-end had way more possibilities.

Collapse
 
darrenbydesign profile image
Darren Sorrels

This is so great! I am super excited to dig into more info about Web Components... I've been afraid to post any of my learnings on it because its so new that I don't want to lead anyone astray with my hacking through it

Although you've inspired me to give writing about my findings a try

Collapse
 
dannyengelman profile image
Danny Engelman

The best way to learn is by explaining/teaching it to others.