Appunti di sviluppo

Web Components e Shadow DOM: componenti riutilizzabili senza framework

Posted on May 15, 2020

Cosa sono i Web Components

I Web Components rappresentano una serie di tecnologie web standard che ci permettono di creare elementi HTML personalizzati, riutilizzabili ed incapsulati. Si tratta di un approccio nativo supportato dai browser moderni, che non richiede l’utilizzo di framework o librerie esterne come React, Angular o Vue.

Le principali tecnologie alla base dei Web Components sono:

  1. Custom Elements: API che permette di definire nuovi elementi HTML
  2. Shadow DOM: Incapsula il markup, lo stile e il comportamento, separandoli dal resto del documento
  3. HTML Templates: Definisce frammenti di HTML che possono essere riutilizzati
  4. HTML Imports: Meccanismo per importare HTML in altri documenti (ormai deprecato)

Vantaggi dei Web Components

I Web Components offrono numerosi vantaggi:

  • Standard nativi del browser: Non richiedono l’installazione di framework o dipendenze esterne
  • Riutilizzabilità: Possono essere utilizzati in qualsiasi applicazione HTML
  • Incapsulamento: Grazie al Shadow DOM, stili e comportamenti sono isolati dal resto della pagina
  • Interoperabilità: Funzionano con tutti i principali framework (React, Vue, Angular)
  • Manutenibilità: Promuovono un approccio modulare allo sviluppo front-end

Shadow DOM: l’isolamento dei componenti

Il Shadow DOM è una delle caratteristiche più potenti dei Web Components. Consente di creare un DOM secondario, isolato dal DOM principale della pagina. Questo significa che:

  • Gli stili CSS definiti nel componente non “fuoriescono” nel resto della pagina
  • Gli stili CSS esterni non influenzano il componente
  • Il markup interno è incapsulato e protetto
  • Si possono usare ID duplicati senza conflitti
// Creazione di un elemento con Shadow DOM
class CustomCard extends HTMLElement {
  constructor() {
    super();
    
    // Creiamo un shadow root
    const shadow = this.attachShadow({mode: 'open'});
    
    // Creiamo gli elementi
    const wrapper = document.createElement('div');
    wrapper.setAttribute('class', 'card');
    
    const title = document.createElement('h2');
    title.textContent = this.getAttribute('title') || 'Default Title';
    
    const content = document.createElement('div');
    content.setAttribute('class', 'card-content');
    content.innerHTML = '<slot></slot>';
    
    // Aggiungiamo stile
    const style = document.createElement('style');
    style.textContent = `
      .card {
        border: 1px solid #ccc;
        border-radius: 5px;
        padding: 16px;
        margin: 16px;
        box-shadow: 0 2px 4px rgba(0,0,0,0.1);
      }
      .card-content {
        margin-top: 8px;
      }
      h2 {
        margin: 0;
        color: #333;
      }
    `;
    
    // Aggiungiamo gli elementi al shadow DOM
    shadow.appendChild(style);
    shadow.appendChild(wrapper);
    wrapper.appendChild(title);
    wrapper.appendChild(content);
  }
}

// Registriamo il custom element
customElements.define('custom-card', CustomCard);

Come utilizzare un Web Component

Una volta definito e registrato, il Web Component può essere utilizzato nel documento HTML proprio come qualsiasi altro elemento HTML:

<custom-card title="Il mio primo Web Component">
  Questo è il contenuto del mio primo Web Component!
</custom-card>

Ciclo di vita dei Custom Elements

I Custom Elements hanno un ciclo di vita gestito attraverso dei callback specifici:

  • constructor: chiamato quando viene creata l’istanza dell’elemento
  • connectedCallback: chiamato quando l’elemento viene aggiunto al DOM
  • disconnectedCallback: chiamato quando l’elemento viene rimosso dal DOM
  • attributeChangedCallback: chiamato quando gli attributi dell’elemento vengono modificati
  • adoptedCallback: chiamato quando l’elemento viene spostato in un nuovo documento
class MyElement extends HTMLElement {
  constructor() {
    super();
    console.log('Elemento costruito!');
  }
  
  connectedCallback() {
    console.log('Elemento aggiunto al DOM!');
  }
  
  disconnectedCallback() {
    console.log('Elemento rimosso dal DOM!');
  }
  
  attributeChangedCallback(name, oldValue, newValue) {
    console.log(`L'attributo ${name} è cambiato da ${oldValue} a ${newValue}`);
  }
  
  // Specifica gli attributi da osservare
  static get observedAttributes() {
    return ['title', 'description'];
  }
}

customElements.define('my-element', MyElement);

Web Components vs Framework

Nel 2020, sempre più sviluppatori stanno esplorando i Web Components come alternativa o complemento ai framework JavaScript. A differenza di React, Vue o Angular, i Web Components:

  • Non richiedono un processo di build
  • Hanno un ciclo di vita più lungo (non dipendono dalle versioni del framework)
  • Hanno prestazioni native senza overhead di framework
  • Funzionano in qualsiasi contesto HTML

Tuttavia, i Web Components non sostituiscono completamente i framework:

  • Mancano di funzionalità avanzate come state management
  • Non hanno un sistema di routing integrato
  • Richiedono maggiore codice boilerplate per funzionalità comuni

Supporto browser

Nel 2020, i Web Components sono supportati nativamente da tutti i browser moderni:

  • Chrome e browsers basati su Chromium (Edge, Opera)
  • Firefox
  • Safari

Internet Explorer rimane l’unico browser che non supporta i Web Components, ma con l’uso di polyfill è possibile garantire la compatibilità.

Conclusioni

I Web Components rappresentano un modo standard e potente per creare componenti riutilizzabili senza dipendere da framework. Offrono un livello di incapsulamento che permette di creare elementi veramente indipendenti e riutilizzabili. Se stai sviluppando librerie di componenti che devono funzionare in diversi contesti o se vuoi ridurre le dipendenze esterne, i Web Components sono sicuramente una tecnologia da considerare nel 2020.

Con la crescente maturità dell’ecosistema e un ottimo supporto browser, è un ottimo momento per iniziare a esplorare questa tecnologia e aggiungere un potente strumento al proprio arsenale di sviluppo web.