OUJOOD.COM
Qu'est-ce que le Shadow DOM ?
JavaScript API – mise à jour 2026Le Shadow DOM résout un problème concret : les conflits CSS. Quand votre page définit .titre { color: red; } et que votre composant définit aussi .titre, l'un écrase l'autre. Sans isolation, écrire des composants réutilisables dans une grande application devient rapidement un exercice de jonglage de spécificité.
Le Shadow DOM attache un arbre DOM privé à un élément HTML. Cet arbre — le shadow tree — a ses propres éléments et ses propres styles. Ce qui est dedans ne sort pas, ce qui est dehors n'entre pas. Point.
Ce n'est pas une nouveauté abstraite : le navigateur l'utilise depuis longtemps pour ses propres éléments. Ouvrez l'inspecteur sur un <input type="range">, activez l'option "Show user agent shadow DOM" dans DevTools — vous verrez le curseur, la piste et le bouton, tous construits avec un Shadow DOM que vous ne pouviez pas modifier jusqu'ici. En 2026, vous pouvez faire exactement la même chose pour vos propres composants.
Trois situations où le Shadow DOM change tout :
- Conflits CSS : une règle
.titredans votre composant n'écrase jamais une règle.titrede la page principale. - Pollution du DOM global : les IDs et classes internes au composant sont invisibles depuis
document.querySelector(). - Maintenabilité : chaque composant porte son propre style — fini les conventions BEM pour éviter les collisions de noms.
Terminologie du Shadow DOM
Quatre termes reviennent dans toute la documentation sur le Shadow DOM. Autant les connaître avant de coder :
- Shadow host : l'élément HTML ordinaire auquel on attache le Shadow DOM — par exemple votre
<carte-info>. - Shadow root : la racine de l'arbre privé, retournée par
attachShadow(). C'est sur ce nœud qu'on injecte le contenu. - Shadow tree : l'ensemble des nœuds DOM à l'intérieur du shadow root.
- Light DOM : le DOM ordinaire de la page, visible dans l'inspecteur sans option spéciale.
Attacher un Shadow DOM avec attachShadow()
attachShadow() crée et attache un Shadow DOM à un élément en une seule ligne. Elle accepte un objet avec une propriété mode qui contrôle l'accessibilité du shadow root depuis l'extérieur.
Mode open
En mode open, le shadow root reste accessible depuis JavaScript via element.shadowRoot. C'est le mode à utiliser dans vos composants — il permet de debugger et de tester depuis l'extérieur.
const hote = document.querySelector('#mon-composant');
// Attacher un Shadow DOM en mode ouvert
const shadowRoot = hote.attachShadow({ mode: 'open' });
// Ajouter du contenu dans le shadow tree
shadowRoot.innerHTML = '<p>Contenu isolé dans le Shadow DOM.</p>';
// Accessible depuis l'extérieur en mode open
console.log(hote.shadowRoot); // Retourne le shadow root
Mode closed
En mode closed, element.shadowRoot retourne null — personne ne peut accéder au shadow tree depuis l'extérieur. C'est le mode que le navigateur utilise pour ses éléments natifs comme <video> ou <input type="range">. Pour vos propres composants, le mode open est généralement suffisant.
const hote = document.querySelector('#mon-composant');
const shadowRoot = hote.attachShadow({ mode: 'closed' });
shadowRoot.innerHTML = '<p>Contenu totalement privé.</p>';
// Inaccessible depuis l'extérieur en mode closed
console.log(hote.shadowRoot); // null
Encapsuler des styles CSS dans le Shadow DOM
Une balise <style> placée dans un shadow root ne s'applique qu'au contenu de ce shadow tree. Même règle dans l'autre sens : les styles globaux de la page n'y entrent pas. C'est une isolation à double sens — ni fuite vers l'extérieur, ni pollution depuis l'extérieur.
class BoutonStyled extends HTMLElement {
connectedCallback() {
const shadow = this.attachShadow({ mode: 'open' });
shadow.innerHTML = `
<style>
/* Ce style n'affecte que l'intérieur du composant */
button {
background: #0066cc;
color: white;
border: none;
padding: 0.6rem 1.4rem;
border-radius: 6px;
cursor: pointer;
font-size: 1rem;
}
button:hover {
background: #0052a3;
}
</style>
<button>Cliquez-moi</button>
`;
}
}
customElements.define('bouton-styled', BoutonStyled);
Même si la page contient une règle CSS globale button { background: red; }, elle n'affectera pas le bouton à l'intérieur du Shadow DOM. L'isolation est totale.
Accéder au contenu du Shadow DOM
En mode open, on navigue dans le shadow tree via element.shadowRoot avec les méthodes DOM habituelles. Ce que document.querySelector() ne voit pas, element.shadowRoot.querySelector() le trouve sans problème.
const composant = document.querySelector('bouton-styled');
// document.querySelector ne voit pas l'intérieur du shadow DOM
console.log(document.querySelector('button')); // null
// Il faut passer par le shadow root
const bouton = composant.shadowRoot.querySelector('button');
console.log(bouton); // <button>Cliquez-moi</button>
// Modifier le contenu depuis l'extérieur
bouton.textContent = 'Merci !';
Shadow DOM et Custom Elements ensemble
Shadow DOM seul protège les styles. Custom Elements seul donne un nom de balise. Les deux ensemble produisent un composant autonome : balise personnalisée + style encapsulé + logique intégrée. On attache le shadow root dans le constructeur, puis on injecte HTML et CSS dans connectedCallback.
class CarteInfo extends HTMLElement {
constructor() {
super();
// Attacher le shadow root dès la construction
this._shadow = this.attachShadow({ mode: 'open' });
}
connectedCallback() {
const titre = this.getAttribute('titre') || 'Titre';
const texte = this.getAttribute('texte') || '';
this._shadow.innerHTML = `
<style>
.carte {
border: 1px solid #ddd;
border-radius: 8px;
padding: 1rem;
font-family: sans-serif;
max-width: 300px;
}
h3 { margin: 0 0 0.5rem; color: #0066cc; }
p { margin: 0; color: #444; font-size: 0.9rem; }
</style>
<div class="carte">
<h3>${titre}</h3>
<p>${texte}</p>
</div>
`;
}
}
customElements.define('carte-info', CarteInfo);
Utilisation dans le HTML :
<carte-info titre="Shadow DOM" texte="Isolation totale du style et du DOM."></carte-info> <carte-info titre="Custom Elements" texte="Vos propres balises HTML natives."></carte-info>
Récapitulatif
attachShadow({ mode: 'open' }) crée un arbre DOM privé dont les styles ne fuient pas vers la page et ne reçoivent rien d'elle. Mode open pour vos composants (debuggable), mode closed pour les éléments natifs du navigateur. Combiné aux Custom Elements, c'est la deuxième brique des Web Components. La troisième — Templates et Slots — vient compléter le mécanisme pour injecter du contenu dynamique dans vos composants.
Par carabde | Mis à jour le 17 avril 2026