DEV Community

Cover image for Dear Web Component
Danny Engelman
Danny Engelman

Posted on

Dear Web Component

How would you address your new found love?

  class ClickButton extends HTMLElement {
    constructor() {
      super(); // Always call super() first 
      this.shadow = this.attachShadow({mode:'open'});
      const buttonElement = document.createElement('button');
      buttonElement.innerHTML = 'Click me';
      const myButtonEl = this.shadow.appendChild(buttonElement);
      myButtonEl.addEventListener('click', () => {
        alert('Button clicked!');
      });
      this.button = buttonElement;
    }
  }
  customElements.define('click-button', ClickButton);
Enter fullscreen mode Exit fullscreen mode

or

  customElements.define('click-button', class extends HTMLElement {
    constructor() {
      const createElement = (tag, props = {}) => Object.assign(document.createElement(tag), props);
      super() // sets AND returns 'this'
        .attachShadow({mode:'open'}) // sets AND returns this.shadowRoot
        .append(
           this.button = createElement( 'button', {
             innerHTML: 'Click me',
             onclick  : (evt) => alert('Button clicked!', this.nodeName)
           })
        );
    }
  });
Enter fullscreen mode Exit fullscreen mode



Top comments (4)

Collapse
 
alaindet profile image
Alain D'Ettorre

Both are fine, it's like the version with the anonymous class seems a particular case of the version with a named class. The named class example encourages convetions, further separation of concerns and it's better for longer web components.

However, the anonymous class has its advantages: registering the component on the bottom of the file plain sucks, because definition and registration are actually two separare things happening on the same file and you just discover it at the very end. Also, not being forced to name the class could be a slight advantage.

Most web components frameworks like Stencil and Lit look like the named class example but solve the annoying problem of registering happening on the bottom by using class decorators

Stencil does it like this

@Component({
  tag: 'click-button',
})
export class ClickButton {
  // ...
}
Enter fullscreen mode Exit fullscreen mode

Lit does it like this

@customElement('click-button')
export class ClickButton extends LitElement {
  // ...
}
Enter fullscreen mode Exit fullscreen mode
Collapse
 
dannyengelman profile image
Danny Engelman

Good comments!
I'd love your review of: connect with the connectedCallback

Collapse
 
noopole profile image
Bruno • Edited
<click-button>
  <template shadowrootmode=open>
    <button onclick="alert('Button clicked!')">Click me</button>
  </template>
</click-button>
Enter fullscreen mode Exit fullscreen mode
Collapse
 
dannyengelman profile image
Danny Engelman • Edited

Good to see back, Bruno

Personally I don't use SSR/SSG much. With the 10 to 40 KB I deliver and applications that require JavaScript anyway, there hardly is any benefit for me.

Getting scope right needs some extra work:

<click-button>
  <template shadowrootmode=open>
    <button onclick="this.getRootNode().host.clicked()">Click me</button>
  </template>
</click-button>
<script>
  customElements.define("click-button", class extends HTMLElement {
    clicked(){
        console.log("Button Click!", this.nodeName)
    }
  });
</script>
Enter fullscreen mode Exit fullscreen mode