Retour à l'accueil

Web Components : mythes et vérité sur les Custom Elements

L’article démystifie les mythes sur les composants web : passage de propriétés, Shadow DOM, hooks. Fournit des solutions en code et met en lumière les forces pour les tableaux de bord et widgets complexes.

Démystification des mythes sur les composants web pour les développeurs
Advertisement 728x90

Web Components : Démystifier les idées reçues et explorer leurs véritables capacités

Les Web Components sont souvent critiqués pour ne permettre, soi-disant, que le passage de propriétés sous forme de chaînes via les attributs. Cette idée reçue découle d'une mécompréhension du mécanisme attributeChangedCallback. Les attributs HTML font partie statique du balisage et ne sont pas directement liés à l'exécution JavaScript. Pour passer des objets, des tableaux ou des primitives, utilisez des accesseurs (getters/setters) dans la classe du composant. Les navigateurs permettent de définir des propriétés de tout type directement via l'API DOM ou des proxies.

class MyElement extends HTMLElement {
  set data(value) {
    this._data = value;
    this.render();
  }
}

Le Shadow DOM offre une isolation des styles et du DOM, protégeant contre les conflits externes. Critiquer cette isolation comme un défaut ignore le choix : les Custom Elements fonctionnent sans Shadow DOM. Pour la personnalisation, utilisez les variables CSS et ::part() :

my-component::part(button) {
  background: var(--accent-color);
}

Le mythe de la duplication des styles : les feuilles de style adoptées (Adopted Style Sheets) permettent d'appliquer des styles partagés à toutes les instances du Shadow DOM.

Google AdInline article slot

Le cycle de vie commence dans le constructeur, pas lors de la connexion au DOM. Les composants sont créés en mémoire et manipulés via DocumentFragment pour la virtualisation sans rendu.

Demi-vérité : Registre et crochets de cycle de vie

Le registre global des Custom Elements nécessite des noms uniques. La solution est d'utiliser des préfixes (par exemple, app-button) et try/catch lors de l'enregistrement :

try {
  customElements.define('app-button', ButtonElement);
} catch (e) {
  console.warn('Conflit de nom :', e);
}

Les collisions sont détectées par les tests. Les espaces de noms plats sont un modèle standard en JS, DNS et HTML.

Google AdInline article slot

Les crochets connectedCallback/disconnectedCallback se déclenchent lors des déplacements dans le DOM. La solution est un indicateur d'initialisation :

connectedCallback() {
  if (this._initialized) return;
  this._initialized = true;
  this.init();
}

La désinscription est impossible, mais c'est un avantage : les navigateurs mettent en cache le constructeur sans surcharge.

Nuances réelles et solutions

L'analyse HTML déclenche connectedCallback sur la balise ouvrante avant le traitement du contenu. Les API DOM ne sont pas disponibles. Utilisez defer ou type="module" pour une initialisation différée. Une alternative est customElements.whenDefined() :

Google AdInline article slot
const button = document.querySelector('app-button');
await customElements.whenDefined('app-button');
button.method();

Pour garantir l'accès aux éléments enfants, utilisez renderCallback ou des crochets similaires.

Forces des Web Components

Les Web Components lient nativement le balisage HTML avec JS. Les balises personnalisées servent de marqueurs pour l'intégration côté serveur ou client sans enfermement propriétaire.

Gestion atomique du cycle de vie : les navigateurs notifient la connexion/déconnexion indépendamment des frameworks.

Un modèle fondamental pour Lit, Symbiote.js et les micro-frontends. Fonctionne avec React, Vue, Angular, SPAs et SSR.

  • Isolation sans surcharge : le Shadow DOM est optionnel.
  • Réactivité native : propriétés + proxies.
  • Polyvalence : des widgets aux tableaux de bord avec WebSocket et graphiques.
  • Virtualisation : DocumentFragment pour des listes de 100 000+ éléments.
  • Stylisation : variables CSS, ::part(), feuilles de style adoptées.

Points clés à retenir

  • Les propriétés de tout type sont passées via des accesseurs ; les attributs sont uniquement pour les chaînes.
  • Le Shadow DOM isole mais peut être désactivé si besoin ; stylisation via variables et ::part.
  • Le registre global est résolu avec des préfixes et des tests ; les collisions sont rares.
  • Les crochets connected/disconnected avec un indicateur évitent l'initialisation en double.
  • L'asynchronisme de l'analyse est corrigé avec defer/module ou whenDefined.

— Editorial Team

Advertisement 728x90

Lire ensuite