Webcomponent : une balise réutilisable, pas un remplaçant de React

Un webcomponent est un composant d’interface fondé sur les standards du navigateur : il permet de créer une balise personnalisée avec son comportement et, si nécessaire, ses styles isolés. Les Web Components servent notamment à partager un même élément entre plusieurs applications, sans imposer leur framework. Leur intérêt dépend toutefois du périmètre choisi et de la qualité de leur interface publique.
Une balise autonome pour partager une fonction précise
Imaginez un indicateur de disponibilité utilisé dans une boutique, un espace client et un outil interne. Plutôt que de réécrire ce composant pour chaque environnement, vous pouvez exposer une balise comme <statut-stock>. Chaque application lui transmet des données et écoute ses événements, tandis que le composant gère son affichage.
Un Web Component n’est pas un framework miniature. Il fournit une unité d’interface réutilisable, pas automatiquement un routeur, une gestion globale de l’état ou une architecture d’application. Il convient particulièrement aux widgets intégrables et aux éléments de design system partagés entre équipes.
Les trois briques à distinguer
- Custom Elements : ils permettent de définir une classe JavaScript associée à une balise HTML personnalisée. Le nom d’un élément autonome doit contenir un tiret, comme message-info.
- Shadow DOM : il crée un arbre DOM rattaché à l’élément, avec une frontière d’encapsulation pour la structure et les styles. Son utilisation reste facultative.
- HTML Templates : la balise <template> contient un fragment inerte que JavaScript peut cloner. Dans un arbre shadow, <slot> permet d’afficher du contenu fourni par la page hôte.
Ces mécanismes se combinent sans être tous obligatoires. Un custom element peut fonctionner sans Shadow DOM ni template. Inversement, un template seul ne devient pas automatiquement un composant interactif.
Créer un premier composant sans outil de compilation
Voici un exemple minimal : une balise affichant un message dans un encadré. Placez le JavaScript suivant dans un fichier chargé par votre page. Le navigateur sait interpréter ces API sans bibliothèque supplémentaire.

class MessageInfo extends HTMLElement { constructor() { super(); const root = this.attachShadow({ mode: 'open' }); root.innerHTML = '<style>:host { display: block; padding: 1rem; border: 1px solid currentColor; border-radius: .5rem; }</style><slot>Information</slot>'; } } customElements.define('message-info', MessageInfo);
Ajoutez ensuite cette balise dans le HTML : <message-info>Votre commande est prête.</message-info>. Le texte fourni apparaît à l’emplacement du slot. Sans contenu, le composant affiche « Information », son contenu de remplacement.
Comprendre ce que fait chaque étape
- Étendre HTMLElement : la classe définit le comportement de votre élément personnalisé.
- Appeler super() : le constructeur initialise correctement la classe parente avant d’utiliser l’instance.
- Attacher un Shadow DOM : attachShadow crée la racine accueillant la structure interne. Le mode open permet d’y accéder via la propriété shadowRoot.
- Enregistrer la balise : customElements.define associe le nom message-info à la classe. Ce nom ne doit pas être enregistré deux fois dans le même registre.
Ici, innerHTML reçoit uniquement une chaîne fixe maîtrisée. N’y injectez pas directement des données utilisateur : pour du texte dynamique, préférez textContent ou construisez explicitement les nœuds nécessaires. Le Shadow DOM n’est pas une protection contre les injections.
Ajouter un cycle de vie sans multiplier les effets de bord
Pour installer un comportement lorsque l’élément rejoint la page, utilisez connectedCallback. Pour retirer des abonnements externes ou arrêter un minuteur après son retrait, utilisez disconnectedCallback. Un élément peut être déconnecté puis reconnecté : l’initialisation doit donc éviter de créer plusieurs fois les mêmes ressources.
Les attributs déclarés dans observedAttributes déclenchent attributeChangedCallback lorsqu’ils changent. Ce mécanisme permet, par exemple, de mettre à jour une variante visuelle. Il ne remplace pas une réflexion sur les données que le composant doit réellement accepter.
Concevoir une interface stable entre le composant et la page
La réutilisabilité repose moins sur la balise que sur son contrat d’utilisation. Documentez les entrées, les sorties et les possibilités de personnalisation avant de multiplier les fonctionnalités. Une équipe doit pouvoir utiliser le composant sans lire son implémentation.
Comprendre et utiliser les composants web avec les API Web — La documentation officielle MDN explique les Web Components, le Shadow DOM et les API JavaScript pour créer des éléments réutilisables et encapsulés.
- Attributs : adaptés aux valeurs textuelles et aux options déclaratives simples. Un attribut booléen HTML repose généralement sur sa présence, pas sur le texte « false ».
- Propriétés JavaScript : préférables pour transmettre des objets, des tableaux ou des valeurs typées.
- Événements : utiles pour signaler une action sans dépendre du gestionnaire d’état de l’application hôte.
- Slots : permettent à la page de fournir du contenu sans modifier la structure interne.
Pour notifier une action au-delà d’une frontière shadow, un CustomEvent peut être émis avec les options bubbles: true et composed: true. Son contenu métier se place dans detail. Choisissez des noms explicites, comme selection-change, et documentez leur signification.
Pensez au premier composant comme à une graine : ce qui mérite d’être conservé n’est pas son apparence initiale, mais sa capacité à pousser dans plusieurs environnements. Testez-le dans une page sobre puis dans une application aux styles très marqués. Si son utilisation exige de connaître ses classes internes ou de modifier son DOM privé, son contrat manque encore de solidité.
Pour la personnalisation, exposez des propriétés CSS personnalisées et, si nécessaire, des éléments avec l’attribut part, ciblables par ::part(). L’encapsulation n’est pas absolue : certaines propriétés héritées, comme la couleur ou la police, peuvent traverser la frontière shadow.
Web Components, React, Vue ou Angular : choisir le bon périmètre
Les Web Components et les frameworks répondent à des besoins qui se recoupent sans se confondre. Les premiers standardisent une frontière de composant dans le navigateur. Les seconds fournissent un modèle plus large pour développer des interfaces et organiser leur évolution.
| Besoin | Approche pertinente | Point de vigilance |
|---|---|---|
| Partager un widget entre plusieurs technologies | Web Component | Définir propriétés, événements et styles publics |
| Construire une application riche et homogène | React, Vue ou Angular | Éviter les frontières techniques inutiles |
| Enrichir ponctuellement une page HTML | JavaScript natif ou custom element | Ne pas complexifier un besoin simple |
| Distribuer un design system transversal | Web Components, éventuellement avec adaptateurs | Soigner la documentation et l’expérience d’intégration |
React, Vue et Angular peuvent intégrer des éléments personnalisés, mais les conventions varient selon leur version et leur configuration. Vérifiez notamment le passage des objets comme propriétés, l’écoute des événements personnalisés et la reconnaissance des balises. Un adaptateur peut simplifier ces échanges sans modifier le composant lui-même.
Les performances ne sont pas automatiquement meilleures. Elles dépendent du JavaScript livré, du nombre d’instances, des mises à jour et du travail effectué à chaque connexion. Mesurez un usage représentatif plutôt que de déduire la rapidité du seul choix technologique.
Valider l’intégration avant de généraliser
Les briques principales des Web Components sont prises en charge par les navigateurs modernes. Cela ne dispense pas de vérifier les versions réellement utilisées, notamment les navigateurs embarqués et les environnements anciens. Les fonctionnalités plus récentes doivent être évaluées séparément.
Le rendu côté serveur demande aussi une stratégie explicite : une balise présente dans le HTML ne produit pas, à elle seule, son interface interne définie en JavaScript. Prévoyez un contenu de remplacement utile ou une solution de rendu adaptée à votre environnement.
- Accessibilité : testez le clavier, le focus, le nom accessible et les technologies d’assistance. Une balise personnalisée n’acquiert pas spontanément la sémantique d’un bouton.
- Robustesse : vérifiez les changements d’attributs, les reconnexions et les instances multiples.
- Intégration : testez les événements et propriétés depuis chaque framework consommateur.
- Maintenance : documentez les évolutions incompatibles du contrat public et évitez les doubles enregistrements.
Commencez par un composant autonome à faible risque, puis confrontez-le à deux usages réels. Cette migration progressive permet de vérifier le bénéfice de l’interopérabilité avant d’étendre l’approche à toute une bibliothèque.