Web Component: fondamenti tecnici | Antreem
Vai al blog

Web Component: fondamenti tecnici

di lettura
Massimo Artizzu
thumbnail

Nella prima parte di questa mini-serie sui Web Component si è discusso delle loro caratteristiche tecniche e dei problemi che si prefissano di risolvere. Ora approfondiremo i dettagli tecnici del loro sviluppo.

È standard consolidato che ogni elemento nativo di HTML sia corrispondente a una classe (nel senso di linguaggio a oggetti, come lo è JavaScript) che estende la classe di base HTMLElement. I nostri Web Component dovranno fare altrettanto.

Un altro punto importante è la possibilità di creare una struttura DOM interna (detta Shadow DOM) che vada a definire elementi visuali e interattivi del componente. E grazie allo Shadow DOM, è possibile definire degli stili specifici e incapsulati del componente, cioè che hanno influenza limitata al solo componente e, viceversa, impediscono che gli stili definiti esternamente abbiano effetto sul componente.

Custom Elements

Il primo “mattone” per la costruzione dei Web Component è la definizione di un nuovo elemento, e questo si fa usando un registro degli elementi “custom”. Il nome dell’elemento – che è quello che useremo nel tag HTML – dovrà essere in minuscolo, dovrà iniziare con una lettera e dovrà contenere un trattino nel mezzo (regola imposta per prevenire possibili conflitti con future definizioni di elementi dello standard HTML, che non hanno mai trattini nel nome).

A questo nome assoceremo la nostra classe JavaScript che estende HTMLElement, come accennato sopra:

class AccordionElement extends HTMLElement {
  constructor() {
    super();
    ...
  }
}
customElements.define('my-accordion', AccordionElement);

A questo punto il nostro elemento sarà definito ed è quindi possibile usare i tag <my-accordion> dentro l’HTML della pagina. Similmente, tutti i tag già presenti in pagina “prenderanno vita” e si attiveranno in base dalla classe che abbiamo definito per l’elemento.

Ciclo di vita

I Web Component sono funzionalmente legati al loro ciclo di vita, che consiste nella definizione di alcuni metodi definiti nella classe sopra menzionata. Tali metodi sono:

  • connectedCallback: metodo chiamato ogni volta che l’elemento viene inserito in pagina;
  • disconnectedCallback: viceversa, questo metodo viene chiamato ogni volta che l’elemento viene rimosso dalla pagina;
  • attributeChangedCallback: questo metodo viene invece chiamato ogni volta che viene aggiunto, rimosso o modificato un attributo sull’elemento (ma solo se presente in elenco esplicito fornito dalla proprietà statica di classe observedAttributes, al fine di ottimizzare le performance);
  • adoptedCallback: usato quando un elemento viene passato da un documento a un altro (generalmente poco usato).

Risulta chiaro come connectedCallback sia il metodo ideale per operazioni di manipolazione del DOM e avvio di MutationObserver o simili, mentre disconnectedCallback si dovrebbe occupare del teardown di queste operazioni. Invece attributeChangedCallback è utile per trasferire il valore degli attributi alle proprietà interne.

Shadow DOM

Già la definizione di un custom element ci porta dentro l’ambito dei Web Component, per cui il nostro elemento si può dire che “viva dentro” il DOM e vi possa operare. Ma uno dei concetti più interessanti dei Web Component è quello dello Shadow DOM.

Avete presente come, a partire da un semplice elemento come <video> o anche solo <input> si ottengano elementi visivi particolari e del tutto assenti da DOM e CSS? Quello che vediamo in quel caso è lo Shadow DOM nativo di tali elementi. Con i Web Component possiamo definire lo shadow DOM dei nostri elementi custom, e così creare layout ed elementi grafici di cui non c’è traccia nell’HTML che scriviamo.

Con il sistema degli slot, inoltre, possiamo anche riposizionare il contenuto incluso all’interno della nostra struttura shadow:

class CardElement extends HTMLElement {
  constructor() {
    super();
    this.attachShadow({ mode: 'open' });
    this.shadowRoot.innerHTML = `<header>
        <slot name="title"></slot>
        <button type="button">Chiudi</button>
      </header>
      <section><slot></slot></section>
      <style>
        :host { ... } ...
      </style>`;
  }
}
<aside>
  <my-card>
    <span slot="title">Notizie</span>
    <p>Il Ministero ha diramato…</p>
  </my-card>
</aside>

Incapsulamento degli stili

L’ultimo elemento inserito nello Shadow DOM dell’esempio sopra è <style>, che viene usato per definire gli stili del DOM. Questo ci porta al prossimo argomento relativo ai Web Component.

Uno degli aspetti più importanti dei componenti con Shadow DOM è l’incapsulamento degli stili. Ne avevamo già parlato in passato, facendo emergere il concetto per cui gli stili globali dell’applicazione e quelli del componente fossero quasi completamente isolati, per cui i primi non influenzano in alcun modo la struttura dello Shadow DOM, e viceversa i secondi non hanno alcun impatto sugli elementi all’esterno del componente.

Questo fa sì che chi sviluppa il Web Component abbia controllo completo sugli stili del componente, e possa decidere quanto e in che modo possano essere cambiati dall’esterno.

Si può infatti decidere per una completa chiusura (anche delle proprietà che normalmente sarebbero ereditate, come il font usato, e che sono causa del “quasi” di cui sopra), oppure per usare solo alcune specifiche proprietà (definite tramite custom properties di CSS), o anche di interi sotto-elementi con l’uso di ::part:

#shadow-dom
  <header part="header">
    <slot name="title"></slot>
    <button type="button" part="close-btn">Chiudi</button>
  </header>
  <section><slot></slot></section>
my-cart::part(header) {
  font-size: 125%;
  color: #444;
}

E dal momento che all’interno dello Shadow DOM si può anche caricare un foglio di stile esterno, si può lasciare completo controllo all’applicazione che fa uso del Web Component di impostargli gli stili in toto, semplicemente modificando tale .css.

E ora?

A questo punto ci si può chiedere: cosa è possibile realizzare con i Web Component? Scendendo più nel particolare, queste sono tra gli interrogativi più comuni:

  • È possibile creare nuovi elementi di input e collegarli con i <form> come gli altri?
  • Come interfacciare correttamente i Web Component con tecnologie assistive?
  • Similmente a quanto avviene con le Single Page Application, come risolvere i problemi di SEO?
  • Cosa si può usare per agevolare lo sviluppo dei Web Component?

Risponderemo a questi punti nella prossima puntata della serie.

Massimo Artizzu
Scritto da
Massimo Artizzu
Formato in Matematica, ma adottato professionalmente nella programmazione, un pallino avuto sin da piccolo. Amante di enigmi e origami, giocatore di rugby per diletto.