On utilise pour cela des Web Components, qui vont utiliser le Shadow DOM pour vivre indépendamment de la page : ils ont en quelque sorte leur propre DOM dédié, tout en pouvant interagir avec l’extérieur si besoin.

Créer et déclarer un composant

Pour créer un composant il faut indiquer au navigateur son nom (qui servira par exemple dans notre HTML), mais aussi la class JavaScript à initialiser pour chaque instance de notre composant :

window.customElements.define('my-app', AppElement)

À quoi ressemble cette fameuse class ? Eh bien de base elle est plutôt simple, puisqu’elle doit juste hériter de HTMLElement :

export class AppElement extends HTMLElement {
}

Ne vous inquiétez pas, elle ne restera pas aussi vide bien longtemps… On va voir tout de suite comment la rendre plus dynamique et utile !

Hériter d’un élément existant

Un composant peut aussi étendre les capacités d’une balise HTML ou d’un composant existant :

export class CustomParagraphElement extends HTMLParagraphElement {
}
window.customElements.define('my-p', CustomParagraphElement, { extends : 'p' })

Utiliser un composant

Pour utiliser notre composant il y a deux méthodes principales :

Avec du HTML

Votre composant étant déclaré par votre JavaScript, vous pouvez utiliser son nom comme une balise HTML classique :

<my-app></my-app>

Sans oublier de charger le JS qui correspond :

<script type="module" src="app.element.js"></script>

Les héritiers d’éléments existants

Si votre composant étend un élément existant vous pouvez utiliser la balise de base avec l’attribut is pour préciser le nom de votre composant :

<p is="my-p"></p>

Avec du JavaScript

Vous pouvez insérer votre composant comme un élément du DOM classique, en ajoutant une instance dans un nœud parent :

import { AppElement } from 'app.element.js' // On importe notre élément

const composant = new AppElement() // On crée une instance de l'élément

document.body.appendChild(composant) // On injecte l'élément dans le DOM

Récupérer les attributs

C’est bien beau tout ça, mais comment j’injecte des valeurs à mon composant, moi ?!

Eh bien en définissant des attributs, pardi !

On va d’abord déclarer quels attributs on veut surveiller (histoire que le navigateur nous prévienne quand ils changent) grâce à une propriété statique (commune à toutes les instances, donc) observedAttributes sur notre composant :

static get observedAttributes() {
	return ['titre'] // On va pouvoir ajouter d'autres attributs à cette liste si besoin
}

En cas de changement le navigateur va alors appeler la méthode attributeChangedCallback de notre composant en précisant le nom de l’attribut, la valeur d’origine et la nouvelle valeur :

attributeChangedCallback(nom, ancienneValeur, nouvelleValeur) {
	if (nom === 'titre') {
		this.titre = nouvelleValeur
	}
}

Félicitations !

Maintenant que vous savez créer vos propres composants, on verra au prochain épisode comment les faire communiquer ensemble !