| [ Web Proxy ] |
| Viewing: https://developer.mozilla.org/fr/docs/Web/API/Web_components/Using_shadow_DOM | [Back] [Original] |
Get to know MDN better
Cette page a t traduite partir de l'anglais par la communaut. Vous pouvez contribuer en rejoignant la communaut francophone sur MDN Web Docs.
Un aspect important des lments personnaliss est l'encapsulation, car un lment personnalis, par dfinition, est une fonctionnalit rutilisable : il peut tre insr dans n'importe quelle page web et on s'attend ce qu'il fonctionne. Il est donc important que le code excut dans la page ne puisse pas accidentellement casser un lment personnalis en modifiant son implmentation interne. Le DOM d'ombre (shadow DOM en anglais) permet d'associer un arbre DOM un lment, et d'avoir l'intrieur de cet arbre inaccessible au JavaScript et au CSS excuts dans la page.
Cet article prsente les bases de l'utilisation du DOM d'ombre.
Element.shadowRoot et l'option mode
Cet article suppose que vous tes dj familier avec le concept de DOM (Document Object Model) une structure arborescente de nuds connects reprsentant les diffrents lments et chanes de caractres apparaissant dans un document balis (gnralement un document HTML dans le cas de documents web). Par exemple, considrez le fragment HTML suivant :
<html lang="fr">
<head>
<meta charset="utf-8" />
<title>Simple exemple de DOM</title>
</head>
<body>
<section>
<img
src="dinosaur.png"
alt="Un tyrannosaurus Rex rouge : un dinosaure bipde se tenant debout comme un humain, avec de petits bras et une large gueule nombreuses dents tranchantes." />
<p>
Nous ajouterons ici un lien vers la
<a href="https://www.mozilla.org/">page d'accueil de Mozilla</a>
</p>
</section>
</body>
</html>
Ce fragment produit la structure DOM suivante :
- HTML
- HEAD
- META charset="utf-8"
- TITLE
- #text: Simple exemple de DOM
- BODY
- SECTION
- IMG src="dinosaur.png" alt="Un tyrannosaurus Rex rouge : un dinosaure bipde se tenant debout comme un humain, avec de petits bras et une large gueule nombreuses dents tranchantes."
- P
- #text: Ici, nous ajouterons un lien vers la
- A href="https://www.mozilla.org/"
- #text: page d'accueil de Mozilla
Le DOM d'ombre permet d'associer des arbres DOM cachs des lments dans l'arbre DOM principal : cet arbre DOM d'ombre commence par une racine d'ombre, sous laquelle vous pouvez attacher n'importe quel lment, comme dans le DOM classique.
[Version SVG du schma montrant l'interaction entre le document, la racine d'ombre et l'hte d'ombre.]
Il existe quelques termes spcifiques au DOM d'ombre connatre :
Vous pouvez manipuler les nuds dans le DOM d'ombre exactement comme les nuds classiques : par exemple, en ajoutant des enfants ou en dfinissant des attributs, en mettant en forme des nuds individuels avec element.style.foo, ou en ajoutant du style tout l'arbre DOM d'ombre l'intrieur d'un lment <style>. La diffrence est qu'aucun code l'intrieur d'un DOM d'ombre ne peut affecter quoi que ce soit l'extrieur, ce qui permet une encapsulation pratique.
Avant que le DOM d'ombre ne soit mis disposition des dveloppeureuses web, les navigateurs l'utilisaient dj pour encapsuler la structure interne d'un lment. Pensez par exemple un lment <video>, avec les contrles par dfaut du navigateur affichs. Tout ce que vous voyez dans le DOM est l'lment <video>, mais il contient une srie de boutons et d'autres contrles l'intrieur de son DOM d'ombre. La spcification du DOM d'ombre vous permet de manipuler le DOM d'ombre de vos propres lments personnaliss.
L'arbre d'ombre et les lments <slot> hritent des attributs dir et lang de leur hte d'ombre.
La page suivante contient deux lments, un lment HTML <div> avec un id de "host", et un lment HTML <span> contenant du texte :
<div id="host"></div>
<span>Je ne suis pas dans le DOM d'ombre</span>
Nous allons utiliser l'lment "host" comme hte d'ombre. Nous appelons attachShadow() sur l'hte pour crer le DOM d'ombre, puis nous pouvons ajouter des nuds au DOM d'ombre comme nous le ferions dans le DOM principal. Dans cet exemple, nous ajoutons un seul lment <span> :
const host = document.querySelector("#host");
const shadow = host.attachShadow({ mode: "open" });
const span = document.createElement("span");
span.textContent = "Je suis dans le DOM d'ombre";
shadow.appendChild(span);
Le rsultat ressemble ceci :
Crer un DOM d'ombre via l'API JavaScript peut tre une bonne option pour les applications rendues ct client. Pour d'autres applications, une interface utilisateur rendue ct serveur peut offrir de meilleures performances et donc une meilleure exprience utilisateur. Dans ces cas, vous pouvez utiliser l'lment <template> pour dfinir le DOM d'ombre de manire dclarative. La cl de ce comportement est l'attribut numr shadowrootmode, qui peut tre dfini sur open ou closed, les mmes valeurs que l'option mode de la mthode attachShadow().
<div id="host">
<template shadowrootmode="open">
<span>Je suis dans le DOM d'ombre</span>
</template>
</div>
Note :
Par dfaut, le contenu de <template> n'est pas affich. Dans ce cas, puisque shadowrootmode="open" a t inclus, la racine d'ombre est rendue. Dans les navigateurs compatibles, le contenu visible l'intrieur de cette racine d'ombre est affich.
Aprs que le navigateur a analys le HTML, il remplace l'lment <template> par son contenu envelopp dans une racine d'ombre qui est attache l'lment parent, le <div id="host"> dans notre exemple. L'arbre DOM rsultant ressemble ceci (il n'y a pas d'lment <template> dans l'arbre DOM) :
- DIV id="host"
- #shadow-root
- SPAN
- #text: Je suis dans le DOM d'ombre
Notez qu'en plus de shadowrootmode, vous pouvez utiliser des attributs de <template> tels que shadowrootclonable et shadowrootdelegatesfocus pour prciser d'autres proprits de la racine d'ombre gnre.
Cela peut paratre peu spectaculaire pour l'instant. Voyons ce qui se passe si le code s'excutant dans la page tente d'accder aux lments du DOM d'ombre.
Cette page est identique la prcdente, sauf que nous avons ajout deux lments <button>.
<div id="host"></div>
<span>Je ne suis pas dans le DOM d'ombre</span>
<br />
<button id="upper" type="button">Mettre en majuscules les lments span</button>
<button id="reload" type="button">Recharger</button>
Cliquer sur le bouton Mettre en majuscules les lments span recherche tous les lments <span> de la page et transforme leur texte en majuscules.
Cliquer sur Recharger recharge simplement la page, pour ressayer.
const host = document.querySelector("#host");
const shadow = host.attachShadow({ mode: "open" });
const span = document.createElement("span");
span.textContent = "Je suis dans le DOM d'ombre";
shadow.appendChild(span);
const upper = document.querySelector("button#upper");
upper.addEventListener("click", () => {
const spans = Array.from(document.querySelectorAll("span"));
for (const span of spans) {
span.textContent = span.textContent.toUpperCase();
}
});
const reload = document.querySelector("#reload");
reload.addEventListener("click", () => document.location.reload());
Si vous cliquez sur Mettre en majuscules les lments span , vous verrez que Document.querySelectorAll() ne trouve pas les lments dans notre DOM d'ombre : ils sont effectivement invisibles pour le JavaScript de la page.
Element.shadowRoot et l'option mode Dans l'exemple cidessous, nous passons l'argument { mode: "open" } attachShadow(). Lorsque mode est dfini sur "open", le JavaScript de la page peut accder l'intrieur de votre DOM d'ombre via la proprit shadowRoot de l'hte d'ombre.
Dans cet exemple, comme prcdemment, le HTML contient l'hte d'ombre, un <span> dans l'arbre DOM principal et deux boutons :
<div id="host"></div>
<span>Je ne suis pas dans le DOM d'ombre</span>
<br />
<button id="upper" type="button">
Mettre en majuscules les lments span du DOM d'ombre
</button>
<button id="reload" type="button">Recharger</button>
Cette fois, le bouton Mettre en majuscules utilise shadowRoot pour trouver les <span> dans le DOM :
const host = document.querySelector("#host");
const shadow = host.attachShadow({ mode: "open" });
const span = document.createElement("span");
span.textContent = "Je suis dans le DOM d'ombre";
shadow.appendChild(span);
const upper = document.querySelector("button#upper");
upper.addEventListener("click", () => {
const spans = Array.from(host.shadowRoot.querySelectorAll("span"));
for (const span of spans) {
span.textContent = span.textContent.toUpperCase();
}
});
const reload = document.querySelector("#reload");
reload.addEventListener("click", () => document.location.reload());
Cette fois, le JavaScript de la page peut accder aux lments internes du DOM d'ombre :
L'argument {mode: "open"} offre la page un moyen de rompre l'encapsulation de votre DOM d'ombre. Si vous ne souhaitez pas donner cette possibilit, passez {mode: "closed"} et shadowRoot renverra null.
Cependant, cela ne doit pas tre considr comme un mcanisme de scurit solide, car il existe des moyens de le contourner, par exemple via des extensions de navigateur s'excutant dans la page. Il s'agit plutt d'une indication que la page ne doit pas accder l'implmentation interne de votre arbre d'ombre.
Dans cette version de la page, le HTML est identique l'original :
<div id="host"></div>
<span>Je ne suis pas dans le DOM d'ombre</span>
En JavaScript, nous crons le DOM d'ombre :
const host = document.querySelector("#host");
const shadow = host.attachShadow({ mode: "open" });
const span = document.createElement("span");
span.textContent = "Je suis dans le DOM d'ombre";
shadow.appendChild(span);
Cette fois, nous avons du CSS ciblant les lments <span> de la page :
span {
color: blue;
border: 1px solid black;
}
Le CSS de la page n'affecte pas les nuds situs l'intrieur du DOM d'ombre :
Dans cette section, nous examinons deux faons d'appliquer des styles dans un arbre de DOM d'ombre :
CSSStyleSheet et en l'attachant la racine d'ombre.<style> dans la dclaration d'un <template>.Dans les deux cas, les styles dfinis dans l'arbre du DOM d'ombre sont limits cet arbre : tout comme les styles de la page n'affectent pas les lments du DOM d'ombre, les styles du DOM d'ombre n'affectent pas les lments du reste de la page.
Pour mettre en forme des lments dans le DOM d'ombre l'aide de feuilles de style constructibles, nous pouvons :
CSSStyleSheet videCSSStyleSheet.replace() ou CSSStyleSheet.replaceSync()ShadowRoot.adoptedStyleSheetsLes rgles dfinies dans la CSSStyleSheet seront limites l'arbre du DOM d'ombre, ainsi qu' tout autre arbre DOM auquel nous l'avons assigne.
Ici, encore une fois, le HTML contient notre hte et un <span> :
<div id="host"></div>
<span>Je ne suis pas dans le DOM d'ombre</span>
Cette fois, nous crons le DOM d'ombre et lui assignons un objet CSSStyleSheet :
const sheet = new CSSStyleSheet();
sheet.replaceSync("span { color: red; border: 2px dotted black;}");
const host = document.querySelector("#host");
const shadow = host.attachShadow({ mode: "open" });
shadow.adoptedStyleSheets = [sheet];
const span = document.createElement("span");
span.textContent = "Je suis dans le DOM d'ombre";
shadow.appendChild(span);
Les styles dfinis dans l'arbre du DOM d'ombre ne s'appliquent pas au reste de la page :
<style> dans des dclarations <template>Une alternative la construction d'objets CSSStyleSheet consiste inclure un lment <style> l'intrieur de l'lment <template> utilis pour dfinir un composant Web.
Dans ce cas, le HTML inclut la dclaration <template> :
<template id="my-element">
<style>
span {
color: red;
border: 2px dotted black;
}
</style>
<span>Je suis dans le DOM d'ombre</span>
</template>
<div id="host"></div>
<span>Je ne suis pas dans le DOM d'ombre</span>
En JavaScript, nous crons le DOM d'ombre et ajoutons le contenu du <template> :
const host = document.querySelector("#host");
const shadow = host.attachShadow({ mode: "open" });
const template = document.getElementById("my-element");
shadow.appendChild(template.content);
Encore une fois, les styles dfinis dans le <template> ne s'appliquent qu' l'intrieur de l'arbre du DOM d'ombre, et pas au reste de la page :
Le choix entre ces options dpend de votre application et de vos prfrences personnelles.
Crer un objet CSSStyleSheet et l'assigner la racine d'ombre via adoptedStyleSheets permet de crer une seule feuille de style et de la partager entre plusieurs arbres DOM. Par exemple, une bibliothque de composants peut crer une seule feuille de style et la partager entre tous les lments personnaliss de cette bibliothque. Le navigateur analysera cette feuille une seule fois. De plus, vous pouvez modifier dynamiquement la feuille de style et propager ces changements tous les composants qui l'utilisent.
L'approche consistant attacher un lment <style> est idale si vous souhaitez tre dclaratif, que vous avez peu de styles et que vous n'avez pas besoin de partager les styles entre diffrents composants.
Sans l'encapsulation fournie par le DOM d'ombre, les lments personnaliss seraient extrmement fragiles. Il serait trop facile pour une page de casser accidentellement le comportement ou la mise en page d'un lment personnalis en excutant du JavaScript ou du CSS sur la page. En tant que dveloppeureuse d'lments personnaliss, vous ne sauriez jamais si les slecteurs applicables l'intrieur de votre lment entraient en conflit avec ceux d'une page qui utilise votre lment personnalis.
Les lments personnaliss sont implments comme une classe qui tend soit la base HTMLElement, soit un lment HTML natif tel que HTMLParagraphElement. En gnral, l'lment personnalis lui-mme est un hte d'ombre, et l'lment cre plusieurs lments sous cette racine pour fournir l'implmentation interne de l'lment.
L'exemple ci-dessous cre un lment personnalis <filled-circle> qui affiche simplement un cercle rempli d'une couleur unie.
class FilledCircle extends HTMLElement {
constructor() {
super();
}
connectedCallback() {
// Crer une racine d'ombre
// L'lment personnalis lui-mme est l'hte d'ombre
const shadow = this.attachShadow({ mode: "open" });
// crer l'implmentation interne
const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
const circle = document.createElementNS(
"http://www.w3.org/2000/svg",
"circle",
);
circle.setAttribute("cx", "50");
circle.setAttribute("cy", "50");
circle.setAttribute("r", "50");
circle.setAttribute("fill", this.getAttribute("color"));
svg.appendChild(circle);
shadow.appendChild(svg);
}
}
customElements.define("filled-circle", FilledCircle);
<filled-circle color="blue"></filled-circle>
Pour d'autres exemples illustrant diffrents aspects de l'implmentation d'lments personnaliss, consultez notre guide sur les lments personnaliss.
Element.attachShadow()ShadowRoot.adoptedStyleSheetsCSSStyleSheet.replace()CSSStyleSheet.replaceSync()<template>:host:host():host-context()::slotted()::partCette page a t modifie le 17 oct. 2025 par les contributeurices du MDN.
Certaines parties de ce contenu sont protges par le droit d'auteur 19982026 des contributeurs individuels de mozilla.org. Contenu disponible sous une licence Creative Commons.
| Web Proxy Viewer | New URL | Original Page |