Develop modern HTML components with Web Components

A 20 Minutes Introduction

#JSBangkok #JSBKK

Overview

  • HTML components and Web Components
  • Core Technologies of Web Components
#JSBangkok #JSBKK

Web Components

  • Custom Elements
  • Shadow DOM
  • Templates and Slots
#JSBangkok #JSBKK

Custom Elements

  • Custom HTML tags created by developers.
  • Extend existing elements or create entirely new ones.
  • Lifecycles:
    • connectedCallback(): inserted into the DOM.
    • disconnectedCallback(): removed from the DOM.
    • attributeChangedCallback(): attributes change.
#JSBangkok #JSBKK

Ex 1: Basic Custom Element

class MyElement extends HTMLElement {
  connectedCallback() {
    this.innerHTML = "<p>Hello, World!</p>";
  }
}
customElements.define('my-element', MyElement);
<!-- Usage: -->
<my-element></my-element>

Simple example of a custom element that adds "Hello, World!" to the DOM.

#JSBangkok #JSBKK

Ex 2: Custom Button with Attributes

class MyButton extends HTMLElement {
  constructor() {
    super();
    this.addEventListener('click', () => alert('Button clicked!'));
  }
  connectedCallback() {
    this.innerHTML = `<button>${this.getAttribute('label')}</button>`;
  }
}
customElements.define('my-button', MyButton);
<!-- Usage: -->
<my-button label="Click me"></my-button>
#JSBangkok #JSBKK

Ex 3: Customize Built-in Element

class ClickableParagraph extends HTMLParagraphElement {
  constructor() {
    super();
    this.addEventListener('click', () => alert('Paragraph clicked!'));
  }
  connectedCallback() {
    this.innerHTML = `Click me: ${this.getAttribute('content')}`;
    this.style.cursor = 'pointer'; // Make it clear that the element is clickable.
    this.style.color = 'blue'; // Add some style.
  }
}
customElements.define('clickable-p', ClickableParagraph, { extends: 'p' });
<!-- Usage: -->
<p is="clickable-p" content="Click me for something"></p>
#JSBangkok #JSBKK

Ex 5: Custom Modal Element

<!-- Usage: -->
<custom-modal id="myModal">
  <p slot="modal-text">This is your modal text.</p>
</custom-modal>
<button onclick="document.getElementById('myModal').open()">Open Modal</button>
#JSBangkok #JSBKK
class CustomModal extends HTMLElement {
  constructor() {
    super();
    this.attachShadow({ mode: 'open' });
    this.shadowRoot.innerHTML = `
      <style>
        .modal {
          display: none;
          // redact because there is no space here.

        }
        .modal-content {
          background-color: white;
          // redact because there is no space here.
        }
      </style>
      <div class="modal">
        <div class="modal-content">
          <span slot="modal-text">
            This is not a modal text you're looking for.
          </span>
        </div>
      </div>
    `;
  }

  connectedCallback() {
    this.modal = this.shadowRoot.querySelector('.modal');
    this.modal.addEventListener('click', () => this.close());
  }

  open() {
    this.modal.style.display = 'block';
  }

  close() {
    this.modal.style.display = 'none';
  }
}

customElements.define('custom-modal', CustomModal);
#JSBangkok #JSBKK

Shadow DOM

  • An encapsulated DOM subtree.
  • Isolates styles and markup from the main document.
  • Avoid CSS and JavaScript conflicts in complex web applications.
    • Also, make it harder to access Global CSS.
#JSBangkok #JSBKK

Ex : Basic Shadow DOM

class MyShadowElement extends HTMLElement {
  constructor() {
    super();
    this.attachShadow({ mode: 'open' });
    this.shadowRoot.innerHTML = `
      <style> p { color: blue; } </style>
      <p>Hello from Shadow DOM</p>
    `;
  }
}
customElements.define('my-shadow-element', MyShadowElement);
<!-- Usage: -->
<my-shadow-element></my-shadow-element>
#JSBangkok #JSBKK

Declarative Shadow DOM

<my-shadow-element>
  <template shadowroot="open">
    <style>
      p { color: blue; }
    </style>
    <p>Hello from Declarative Shadow DOM</p>
  </template>
</my-shadow-element>
#JSBangkok #JSBKK

Shadow DOM: Pros and Cons

  • Isolates component styles and DOM structure from the rest of the page.
  • Reusable encapsulated components.
  • Styles defined within a shadow root are isolated from the global scope.
  • Developers must learn how to manage scoped styles and lifecycle events.
  • Components in different shadow trees cannot easily communicate.
#JSBangkok #JSBKK

Ex : Custom Card Component

<!-- Usage: -->
<custom-card>
  <h2 slot="title">Card Title</h2>
  <p slot="content">Card content goes here.</p>
</custom-card>
#JSBangkok #JSBKK
class CustomCard extends HTMLElement {
  constructor() {
    super();
    this.attachShadow({ mode: 'open' });
    this.shadowRoot.innerHTML = `
      <style>
        .card {
          border: 1px solid #ddd;
          padding: 20px;
          box-shadow: 2px 2px 10px rgba(0, 0, 0, 0.1);
        }
      </style>
      <div class="card">
        <slot name="title"> [object Object] </slot>
        <slot name="content"> [object Object] </slot>
      </div>
    `;
  }
}
customElements.define('custom-card', CustomCard);
#JSBangkok #JSBKK

Templates

  • A way to define HTML chunks for later reuse.
  • Templates are not rendered when the page loads, only when explicitly instantiated.
#JSBangkok #JSBKK

Templates Example

<template id="myTemplate">
  <p>This is content from the template.</p>
</template>
<!-- <template> is hidden and won't appear on the page initially. -->


<div id="contentArea"></div>
const template = document.getElementById('myTemplate');
const contentArea = document.getElementById('contentArea');

contentArea.appendChild(template.content.cloneNode(true));
#JSBangkok #JSBKK

Templates: Pros and Cons

  • HTML structures defined once and reused multiple times.
  • Templates are not displayed until needed, improving performance.
  • Must be activated via JavaScript.
  • Templates are static by nature.
#JSBangkok #JSBKK

Slots

  • Mechanism for distributing content inside custom elements.
  • Named and default slots for content distribution.
#JSBangkok #JSBKK

Advantages of Using Web Components

  • ...
#JSBangkok #JSBKK

Advantages of Using Web Components

  • Encapsulation of styles and behavior
  • Reusability across frameworks (React, Vue, Angular)
  • Can fit into most project structures
#JSBangkok #JSBKK

Where to go next

https://custom-elements-everywhere.com/

google "github custom elements everywhere"
see supported frameworks and code they use for testing.

#JSBangkok #JSBKK

Q & A

#JSBangkok #JSBKK
#JSBangkok #JSBKK

(Sat) 19 October 2024, 14:35 @Hall 2 at True Digital Park West Web Components have been around for more than 10 years. They should be one of the concepts we teach to young developers, but somehow, with the rise of promising JavaScript frameworks like Next.js, Nuxt.js, and various others, developing modern frontend applications with Web Components is still not widely known. In this talk, I want to show how we can develop modern JavaScript components with only native APIs that most browsers support. How they can be used with or inside most JavaScript frameworks without problems.

- Advantages and Practices

HTML Components are built-in likes <p> <h1> <div> <section> Web Components are a set of technologies that offer encapsulation and reusable components So, to develop Web Components could said that it is to develop custom HTML components.

Introduce Web Components as a way to create encapsulated, reusable elements natively in the browser without frameworks. Mention key technologies and their growing importance in 2024.

--- # Custom Elements: Pros - **Encapsulation:** Custom elements bundle HTML, CSS, and JS behavior. - **Reusability:** Can be reused across different parts of the application. - **Framework-agnostic:** Works in any environment (React, Vue, Angular). - **Native browser support:** Supported without external libraries. --- # Custom Elements: Cons - **Browser compatibility:** Some features might require polyfills in older browsers. - **Learning curve:** Developers need to learn about lifecycle callbacks and custom element APIs. - **Styling challenges:** Managing scoped styles and integration with external stylesheets can be tricky.

Intentional

<style> .modal { display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.5); } .modal-content { background-color: white; margin: 15% auto; padding: 20px; width: 80%; } </style>

- Introduced to make Shadow DOM more declarative in HTML. - Useful for server-side rendering (SSR). - Allows attaching shadow roots directly in HTML.

# Working with Shadow DOM - ShadowRoot, shadow trees, and light DOM - Styling within Shadow DOM - Scoping and sharing styles - Handling CSS isolation

Pros:

Cons:

Pros

Cons

Looking at the React full support in 19 Survey Repo: testing in each framework.