W3docs

Web Components

Apprenez les web components JavaScript : éléments personnalisés, Shadow DOM, templates HTML, slots et callbacks de cycle de vie, avec des exemples pratiques.

Les web components vous permettent de créer vos propres éléments HTML réutilisables et encapsulés — des balises personnalisées comme <user-card> ou <star-rating> qui embarquent leur propre balisage, leurs styles et leur comportement. Comme ils reposent sur des API natives du navigateur, ils fonctionnent dans n'importe quel framework (ou sans framework du tout) et maintiennent leurs éléments internes isolés du reste de la page. Ce guide couvre les trois blocs constitutifs des web components, explique comment en construire un de zéro, et se termine par les hooks de cycle de vie et les bonnes pratiques.

Quand utiliser les web components ?

Optez pour les web components lorsque vous souhaitez un widget d'interface autonome qui :

  • Fonctionne partout — le même <my-widget> s'intègre dans une page React, Vue, HTML pur ou rendue côté serveur, sans étape de build.
  • Reste isolé — ses styles ne peuvent pas fuir vers l'extérieur et les styles de la page ne peuvent pas le contaminer, grâce au Shadow DOM.
  • Se distribue en un seul fichier — le balisage, le style et la logique coexistent, ce qui facilite la distribution et la réutilisation du composant.

Les design systems, les widgets intégrables et les bibliothèques de composants partagés sont les cas d'usage les plus courants.

Introduction aux Web Components

Les web components constituent un ensemble d'API de la plateforme web qui vous permettent de créer de nouvelles balises HTML personnalisées, réutilisables et encapsulées. Trois technologies fonctionnent ensemble :

  • Custom Elements — définissent de nouvelles balises HTML et leur comportement.
  • Shadow DOM — encapsule le balisage et les styles d'un composant de sorte qu'ils soient limités à l'élément.
  • HTML Templates — déclarent des fragments de balisage inerte réutilisables que vous instanciez à l'exécution.

Custom Elements

Les custom elements définissent de nouvelles balises HTML et leur comportement. Ils reposent sur les classes JavaScript : un custom element est une classe qui étend HTMLElement. Une fois enregistrée, la balise peut être utilisée comme n'importe quel élément HTML standard.

<div>
  <script>
    class MyElement extends HTMLElement {
      constructor() {
        super();
        this.attachShadow({ mode: 'open' });
        this.shadowRoot.innerHTML = '<p>Hello, World!</p>';
      }
    }
    customElements.define('my-element', MyElement);
  </script>
  <my-element></my-element>
</div>

Cet extrait de code montre comment créer un élément HTML personnalisé appelé my-element. La classe MyElement étend HTMLElement, attache un shadow DOM pour encapsuler son contenu et insère un simple paragraphe avec le texte "Hello, World!".

Shadow DOM

Le Shadow DOM fournit l'encapsulation pour vos custom elements. Il vous permet d'attacher un arbre DOM séparé et caché (l'arbre fantôme) à un élément, en limitant ses styles et son balisage à l'élément lui-même. Pour approfondir le sujet, consultez le chapitre dédié au Shadow DOM JavaScript.

<div>
  <script>
    class ShadowElement extends HTMLElement {
      constructor() {
        super();
        let shadow = this.attachShadow({ mode: 'open' });
        shadow.innerHTML = `
          <style>
            p { color: blue; }
          </style>
          <p>Shadow DOM content</p>
        `;
      }
    }
    customElements.define('shadow-element', ShadowElement);
  </script>
  <shadow-element></shadow-element>
</div>

Dans cet exemple, la classe ShadowElement étend HTMLElement et attache une racine shadow à l'élément. Le paramètre mode: 'open' indique que le shadow DOM est accessible via JavaScript. Lorsque mode est défini sur 'open', la racine shadow est accessible via la propriété element.shadowRoot. Si mode est défini sur 'closed', la racine shadow n'est pas accessible de l'extérieur, ce qui renforce l'encapsulation et empêche les scripts externes de manipuler directement le shadow DOM.

Au sein du shadow DOM, on définit des styles et du contenu HTML. Les styles (dans ce cas, un paragraphe stylisé en texte bleu) sont limités au shadow DOM, ce qui garantit qu'ils n'affectent pas les autres éléments de la page. Cette encapsulation est bénéfique pour créer des composants réutilisables avec un style et un comportement cohérents, quel que soit le contexte dans lequel ils sont utilisés.

Avertissement

Utilisez des styles locaux au sein du Shadow DOM pour éviter les fuites de styles et garantir que les styles du composant sont bien encapsulés.

Pour en savoir plus sur la portée du CSS dans un arbre shadow — notamment :host et les propriétés personnalisées CSS qui peuvent traverser la frontière — consultez Stylisation du Shadow DOM.

HTML Templates

Les HTML templates vous permettent de définir des fragments HTML réutilisables qui sont inertes — ils sont analysés mais pas rendus, et leurs scripts ne s'exécutent pas — jusqu'à ce que vous les cloniez et les insériez à l'exécution. L'élément <template> est la méthode standard pour ce faire.

<div>
  <template id="my-template">
    <style>
      p { color: red; }
    </style>
    <p>This is a template content</p>
  </template>
  <script>
    const template = document.getElementById('my-template').content;
    document.body.appendChild(template.cloneNode(true));
  </script>
</div>

Cet exemple montre comment utiliser les HTML templates. La balise <template> contient du HTML et des styles qui ne sont pas rendus immédiatement. Le script clone le contenu du template et l'ajoute au corps du document, le rendant ainsi visible.

Créer votre premier Web Component

Parcourons ensemble le processus de création d'un web component pleinement fonctionnel pouvant être utilisé dans différents projets.

Étape 1 : Définir le composant

Créez une nouvelle classe qui étend HTMLElement.

<div>
  <script>
    class MyComponent extends HTMLElement {
      constructor() {
        super();
        const shadow = this.attachShadow({ mode: 'open' });
        shadow.innerHTML = 'Hello, World!';
      }
    }
    customElements.define('my-component', MyComponent);
  </script>
  <my-component></my-component>
</div>

Cet extrait pose les bases d'un web component appelé my-component. Il définit une classe qui étend HTMLElement et attache un shadow DOM, le préparant à une personnalisation ultérieure.

Étape 2 : Ajouter des styles et des templates

Utilisez le Shadow DOM pour encapsuler les styles et les templates.

<div>
  <script>
    class MyStyledComponent extends HTMLElement {
      constructor() {
        super();
        let shadow = this.attachShadow({ mode: 'open' });
        shadow.innerHTML = `
          <style>
            p { font-size: 20px; color: green; }
          </style>
          <p>This is my styled component!</p>
        `;
      }
    }
    customElements.define('my-styled-component', MyStyledComponent);
  </script>
  <my-styled-component></my-styled-component>
</div>

Cet extrait améliore my-styled-component en ajoutant des styles encapsulés dans le shadow DOM. Le paragraphe au sein du composant est stylisé en vert avec une taille de police augmentée.

Étape 3 : Ajouter de l'interactivité

Ajoutez du JavaScript pour rendre votre composant interactif.

<div>
  <script>
    class InteractiveComponent extends HTMLElement {
      constructor() {
        super();
        this.attachShadow({ mode: 'open' });
        this.shadowRoot.innerHTML = `
          <style>
            p { font-size: 20px; }
          </style>
          <p>This is interactive!</p>
          <button>Click me</button>
        `;
        this.shadowRoot.querySelector('button').addEventListener('click', () => {
          this.shadowRoot.querySelector('p').textContent = 'You clicked!';
        });
      }
    }
    customElements.define('interactive-component', InteractiveComponent);
  </script>
  <interactive-component></interactive-component>
</div>

Cet exemple montre comment rendre un web component interactif. Le composant InteractiveComponent comprend un bouton qui, lorsqu'on clique dessus, modifie le contenu textuel d'un paragraphe au sein du composant.

Techniques avancées pour les Web Components

Callbacks de cycle de vie

Les custom elements disposent de callbacks de cycle de vie qui vous permettent d'exécuter du code lors de phases spécifiques de la vie d'un élément.

<div>
  <script>
    class LifecycleComponent extends HTMLElement {
      constructor() {
        super();
        this.attachShadow({ mode: 'open' });
      }
      connectedCallback() {
        this.shadowRoot.innerHTML = '<p>Element added to page.</p>';
      }
      disconnectedCallback() {
        console.log('Element removed from page.');
      }
    }
    customElements.define('lifecycle-component', LifecycleComponent);
  </script>
  <lifecycle-component></lifecycle-component>
</div>

Cet extrait illustre l'utilisation des callbacks de cycle de vie dans les web components. Le composant LifecycleComponent met à jour son contenu lorsqu'il est ajouté à la page et enregistre un message lorsqu'il est supprimé.

Gestion des changements d'attributs

Réagissez aux changements des attributs d'un élément en définissant le tableau observedAttributes et en implémentant la méthode attributeChangedCallback.

<div>
  <script>
    class AttributeComponent extends HTMLElement {
      static get observedAttributes() {
        return ['data-text'];
      }
      constructor() {
        super();
        this.attachShadow({ mode: 'open' });
        this.shadowRoot.innerHTML = '<p></p>';
      }
      attributeChangedCallback(name, oldValue, newValue) {
        if (name === 'data-text') {
          this.shadowRoot.querySelector('p').textContent = newValue;
        }
      }
    }
    customElements.define('attribute-component', AttributeComponent);
  </script>
  <attribute-component data-text="Initial text"></attribute-component>
  <script>
    const element = document.querySelector('attribute-component');
    setTimeout(() => {
      element.setAttribute('data-text', 'Updated text');
    }, 2000);
  </script>
</div>

Cet exemple montre comment gérer les changements d'attributs dans un web component. Le composant AttributeComponent met à jour son contenu interne en fonction des modifications apportées à l'attribut data-text. Notez que attributeChangedCallback ne se déclenche que pour les attributs listés dans observedAttributes — sans cette liste, les changements d'attributs sont ignorés.

Les quatre callbacks de cycle de vie des custom elements sont :

CallbackMoment d'exécution
constructor()Lorsque l'élément est créé ou mis à niveau. Configurez l'état initial ici, mais évitez de toucher aux attributs ou au DOM enfant.
connectedCallback()Chaque fois que l'élément est inséré dans le document. C'est le meilleur endroit pour effectuer le rendu et ajouter des écouteurs d'événements.
disconnectedCallback()Chaque fois que l'élément est supprimé du document. Nettoyez les écouteurs et les minuteurs ici.
attributeChangedCallback(name, oldVal, newVal)Lorsqu'un attribut observé change. Nécessite un getter statique observedAttributes.

Distribution du contenu enfant avec les slots

Un <slot> permet à un composant de rendre le balisage placé par l'utilisateur entre ses balises, de sorte que les consommateurs puissent injecter leur propre contenu. C'est la base de la composition avec les web components — consultez Shadow DOM, slots et composition pour avoir une vue d'ensemble complète.

<div>
  <script>
    class CardBox extends HTMLElement {
      constructor() {
        super();
        this.attachShadow({ mode: 'open' });
        this.shadowRoot.innerHTML = `
          <style>
            .box { border: 1px solid #ccc; padding: 8px; }
          </style>
          <div class="box"><slot>Default content</slot></div>
        `;
      }
    }
    customElements.define('card-box', CardBox);
  </script>
  <card-box>Passed-in content</card-box>
  <card-box></card-box>
</div>

Le premier <card-box> affiche "Passed-in content" dans la boîte stylisée ; le second revient au contenu par défaut du slot "Default content".

Bonnes pratiques pour les Web Components

Utiliser le Shadow DOM judicieusement

Encapsulez les styles et les scripts dans le Shadow DOM pour éviter les conflits avec les autres éléments de la page.

Respecter les conventions de nommage

Les custom elements doivent contenir un trait d'union dans leur nom (par exemple, my-card, et non mycard) afin d'éviter les conflits avec les éléments HTML standard actuels et futurs. L'enregistrement d'un nom sans trait d'union génère une erreur.

Maintenir la modularité des composants

Créez des composants petits et réutilisables pour maintenir votre base de code maintenable et évolutive.

Éviter les styles globaux

Utilisez des styles locaux au sein du Shadow DOM pour prévenir les fuites de styles et garantir que les styles du composant sont bien encapsulés.

Documentation et tests

Documentez bien vos composants et rédigez des tests pour vous assurer qu'ils fonctionnent comme prévu dans différents navigateurs et cas d'utilisation.

Conclusion

Les web components constituent une fonctionnalité polyvalente et puissante du développement web moderne, permettant la création d'éléments personnalisés réutilisables et encapsulés. En comprenant et en utilisant les Custom Elements, le Shadow DOM et les HTML Templates, vous pouvez créer des applications web modulaires, maintenables et évolutives. Ce guide vous a fourni les connaissances et les exemples nécessaires pour démarrer avec les web components, vous permettant de les implémenter efficacement dans vos projets.

Pour aller plus loin, explorez le Shadow DOM JavaScript, comment le Shadow DOM et les événements interagissent, et l'élément <template> en profondeur.

Pratique

Pratique
Laquelle des affirmations suivantes sur les Web Components est correcte ?
Laquelle des affirmations suivantes sur les Web Components est correcte ?
Was this page helpful?