// html · Web Platform Advent #5
Web Components: Custom Elements, Shadow DOM e template
Crea elementi HTML riutilizzabili con le API native dei Web Components — definire un Custom Element, incapsulare gli stili con lo Shadow DOM, clonare un <template> e passare dati con gli attributi.
I Web Components sono un insieme di API native del browser che ti permettono di creare i tuoi elementi HTML riutilizzabili — senza bisogno di un framework. Un componente che distribuisci funziona allo stesso modo in HTML puro, React, Vue o Svelte, perché è semplicemente un elemento che il browser comprende. Tre API lo rendono possibile: i Custom Elements, lo Shadow DOM e il tag <template>.
Custom Elements
Un Custom Element è una classe che estende HTMLElement, registrata con un nome di tag che deve contenere un trattino (così non potrà mai entrare in conflitto con un futuro tag integrato):
class GreetingCard extends HTMLElement {
connectedCallback() {
const p = document.createElement('p');
p.textContent = 'Hello from a custom element!';
this.append(p);
}
}
customElements.define('greeting-card', GreetingCard); Una volta definito, lo usi come qualsiasi altro tag:
<greeting-card></greeting-card> La classe ti offre i callback del ciclo di vita. I più utili sono connectedCallback (l'elemento è stato aggiunto alla pagina), disconnectedCallback (è stato rimosso) e attributeChangedCallback (un attributo osservato è cambiato).
Reagire agli attributi
Per passare dati, leggi gli attributi — esattamente come src su un'immagine. Dichiara quali osservare con un getter statico observedAttributes, poi rispondi in attributeChangedCallback. Costruire il nodo con textContent mantiene al sicuro i valori forniti dall'utente:
class GreetingCard extends HTMLElement {
static get observedAttributes() {
return ['name'];
}
attributeChangedCallback(attr, oldVal, newVal) {
if (attr === 'name') this.render();
}
connectedCallback() {
this.render();
}
render() {
const name = this.getAttribute('name') || 'friend';
this.replaceChildren();
const p = document.createElement('p');
p.textContent = 'Hello, ' + name + '!';
this.append(p);
}
}
customElements.define('greeting-card', GreetingCard); Ora <greeting-card name="Ada"></greeting-card> visualizza "Hello, Ada!", e cambiare l'attributo dal vivo lo ridisegna.
Lo Shadow DOM: vero incapsulamento
Lo Shadow DOM conferisce a un elemento un sottoalbero privato i cui stili e markup sono isolati dal resto della pagina. Uno <style> al suo interno non può mai trapelare all'esterno, e il CSS esterno non può mai raggiungerlo per sbaglio. Costruiscilo con l'API del DOM e uno <slot> per il contenuto proiettato:
class FancyButton extends HTMLElement {
connectedCallback() {
const shadow = this.attachShadow({ mode: 'open' });
const style = document.createElement('style');
style.textContent =
'button { background:#2563eb; color:#fff; border:0;' +
' border-radius:8px; padding:.6rem 1rem; }';
const button = document.createElement('button');
button.append(document.createElement('slot'));
shadow.append(style, button);
}
}
customElements.define('fancy-button', FancyButton); Lo <slot> è un segnaposto: qualunque cosa tu metta tra i tag — <fancy-button>Save</fancy-button> — viene proiettata in quel punto, così il componente avvolge il tuo contenuto senza sostituirlo.
Template: clona una volta, riutilizza a basso costo
L'elemento <template> contiene markup inerte che viene analizzato ma non visualizzato finché non lo cloni. È il modo efficiente per produrre strutture ripetute:
<template id="row-tpl">
<li><span class="label"></span></li>
</template>
<script>
const tpl = document.getElementById('row-tpl');
const node = tpl.content.cloneNode(true);
node.querySelector('.label').textContent = 'Item 1';
document.querySelector('ul').append(node);
</script> I tre pezzi insieme
| API | Ti offre |
|---|---|
| Custom Elements | I tuoi tag con callback del ciclo di vita |
| Shadow DOM | Incapsulamento di stile e markup, slot |
<template> | Markup inerte riutilizzabile e clonabile |
Raramente hai bisogno di tutti e tre insieme. Un semplice wrapper potrebbe usare solo un Custom Element; un widget stilizzato e autonomo combina un Custom Element con lo Shadow DOM e uno slot. Poiché il risultato è puro DOM, si inserisce in qualsiasi stack e sopravvive a qualunque framework fosse popolare nell'anno in cui l'hai scritto.