Get to know MDN better
このページはコミュニティーの尽力で英語から翻訳されました。MDN Web Docs コミュニティーについてもっと知り、仲間になるにはこちらから。
カスタム要素の重要な側面の一つがカプセル化です。なぜなら、カスタム要素は定義上、再利用可能な機能の一部であり、任意のウェブページにドロップして動作させることが期待されるからです。そのため、ページで実行されるコードが、内部実装を変更することでカスタム要素を誤って壊すことがないようにすることが重要です。シャドウ DOM を使用すると、DOM ツリーを要素に割り当て、ページで実行される JavaScript や CSS からこのツリーの内部を隠すことができます。
この記事では、シャドウ DOM の使用法の基本について説明します。
この記事は、すでにあなたが DOM (Document Object Model) の概念を理解していることを想定しています。これはツリー上の構造で、接続されたノードがマークアップ文書(ウェブ文書の場合は通常 HTML 文書)に現れるさまざまな要素や文字列を表します。例として、以下のような HTML の断片を考えてみましょう。
このフラグメントは、以下の DOM 構造を生成します(ホワイトスペースのみのテキストノードを除く)。
- HTML - HEAD - META charset="utf-8" - TITLE - #text: DOM example - BODY - SECTION - IMG src="dinosaur.png" alt="A red Tyrannosaurus Rex." - P - #text: Here we will add a link to the - A href="https://www.mozilla.org/" - #text: Mozilla homepageシャドウ DOM により、通常の DOM ツリーの要素の下に隠れた DOM ツリーを取り付けることができます。このシャドウ DOM ツリーはシャドウルートから始まり、その下には普通の DOM ツリーと同様に任意の要素を追加することができます。
以下にシャドウ DOM における用語を定義します。
シャドウ DOM 内のノードには、シャドウでないノードと全く同じように影響を与えることができます。たとえば、子を追加したり、属性を設定したり、element.style.foo を使用して個々のノードのスタイルを設定したり、 <style> 要素内でシャドウ DOM ツリー全体へのスタイルを追加したりすることができます。違いは、シャドウ DOM 内のどのコードもその外の何かに影響を与えることができず、便利なカプセル化ができることです。
ウェブ開発者がシャドウ DOM を利用できるようになる前から、ブラウザーはすでに要素の内部構造をカプセル化するためにシャドウ DOM を使用していました。例えば、既定のブラウザーコントロールが公開されている <video> 要素を思い浮かべてください。 DOM には <video> 要素しか表示されませんが、そのシャドウ DOM の内部には、一連のボタンやその他のコントロールが含まれています。 シャドウ DOM 仕様書では、自分自身でカスタマイズした要素のシャドウ DOM を操作できるようにします。
シャドウツリーと <slot> 要素は、シャドウホストから dir および lang 属性を継承しています。
次のページには、2つの要素が含まれています。<div> 要素で id が "host" であるものと、テキストを格納する <span> 要素です。
"host" の要素をシャドウホストとして使用します。このホスト上で attachShadow() を呼び出してシャドウ DOM を作成し、このシャドウ DOM には、メイン DOM に対して行うのと同じようにノードを追加することができます。この例では、単一の <span> 要素を追加します。
結果は次のようになります。
シャドウ DOM を作成するのに JavaScript API を使用する方法は、クライアント側でレンダリングされるアプリケーションには良い選択肢かもしれません。それ以外のアプリケーションでは、サーバー側でレンダリングされた UI の方がパフォーマンスが良いことが多く、その結果、より使い勝手の良いものにできる可能性があります。そのような場合、<template> 要素を使用してシャドウ DOM を宣言的に定義することができます。この動作の鍵となるのは列挙型の shadowrootmode 属性です。これは open または closed のどちらかに設定することができ、attachShadow() メソッドの mode オプションと同じ値です。
メモ: 既定では、<template> の内容は表示されません。この場合、shadowrootmode="open" が記載されているため、シャドウルートがレンダリングされます。対応しているブラウザーでは、そのシャドウルート内の可視コンテンツが表示されます。
ブラウザーが HTML を解釈し終えると、 <template> 要素は、親要素(この例では <div id="host">)に追加されたシャドウルートにラップされた内容に置き換えられます。その結果の DOM ツリーは次のようになります(DOM ツリーには <template> 要素はありません)。
- DIV id="host" - #shadow-root - SPAN - #text: I'm in the shadow DOMなお、shadowrootmode に加えて、 <template> の shadowrootclonable や shadowrootdelegatesfocus 属性などの使用して、生成されるシャドウルートに他のプロパティを指定することができます。
ここまでは、それほど多くはないように見えるかもしれません。しかし、ページで実行しているコードが、シャドウ DOM 内の要素にアクセスしようとした場合、何が起こるか見ていきましょう。
このページは、2 つの <button> 要素を追加したことを除いて、先のページと同じです。
"Uppercase span elements" ボタンをクリックすると、ページ内のすべての <span> 要素を探し、そのテキストを大文字に変換します。 "Reload" ボタンをクリックすると、ページが再読み込みされるので、もう一度試してみることができます。
"Uppercase span elements" をクリックすると、Document.querySelectorAll() が私たちのシャドウ DOM 内の要素を探していないことがわかります。それらはページ内の JavaScript から効果的に隠されています。
上記の例では、引数 { mode: "open" } を attachShadow() に渡しています。 モードが "open" に設定されている場合、ページ内の JavaScript は、シャドウホストの shadowRoot プロパティを通じて、シャドウ DOM の内部にアクセスすることができます。
この例では、前述の例と同様に、HTML はシャドウホスト、メインの DOM ツリー内の <span> 要素、および 2 つのボタンを含んでいます。
この時点では、"Uppercase" ボタンは shadowRoot を使用して DOM 内の <span> 要素を探します。
この時点では、ページで実行されている JavaScript は、シャドウ DOM の内部にアクセスすることができます。
引数 {mode: "open"} は、ページにシャドウ DOM のカプセル化を解除する方法を提供します。ページにこの機能を与えたくない場合は、代わりに {mode: "closed"} を渡すと、shadowRoot は null を返します。
しかし、これを強力なセキュリティの仕組みだと考えるべきではありませ ん。例えば、ページで実行するブラウザー拡張機能など、回避する方法があるからです。むしろ、ページがシャドウ DOM ツリーの内部にアクセスすべきではないことを示すものです。
このページのこのバージョンでは、HTML は元のバージョンと同じです。
JavaScript では、シャドウ DOM を作成します。
今回は、ページ内の <span> 要素を対象とする CSS を指定します。
ページの CSS は、シャドウ DOM 内のノードには影響しません。
この節では、シャドウ DOM ツリー内でスタイル設定を行う 2 つの異なる方法を見ていきます。
どちらの場合も、シャドウ DOM ツリーで定義されたスタイルはそのツリーにのみ適用されるため、ページスタイルがシャドウ DOM の要素に影響を与えないのと同様に、シャドウ DOM スタイルはページの他の部分の要素に影響を与えません。
シャドウ DOM のページ要素を構築可能なスタイルシートでスタイル設定するには、次の方法があります。
CSSStyleSheet で定義されたルールは、シャドウ DOM ツリーだけでなく、他にも割り当てられた DOM ツリーにも適用されます。
ここで、再び、ホストと <span> を格納する HTML は次のとおりです。
今回は、シャドウ DOM を作成し、CSSStyleSheet オブジェクトを割り当てます。
シャドウ DOM ツリーで定義されたスタイルは、ページの他の部分には適用されません。
CSSStyleSheet オブジェクトを作成する代わりに、<style> 要素をウェブコンポーネントを定義するために使用する <template> 要素内に記載することもできます。
この場合、HTML には次の <template> 宣言が含まれます。
JavaScript で、シャドウ DOM を作成し、そこに <template> の内容を追加します。
繰り返しになりますが、<template> で定義されたスタイルはシャドウ DOM ツリー内でのみ適用され、ページの他の部分には適用されません。
どのオプションを使用するかは、アプリケーションと環境設定によって異なります。
CSSStyleSheet を作成し、adoptedStyleSheets を使用してシャドウルートに割り当てることで、単一のスタイルシートを作成し、それを複数の DOM ツリーで共有することができます。例えば、コンポーネントライブラリーで単一のスタイルシートを作成し、そのライブラリーに属するすべてのカスタム要素で共有することができます。このスタイルシートは、ブラウザーによって一度だけ解釈されます。また、スタイルシートに動的な変更を加え、そのシートを使用するすべてのコンポーネントに伝搬させることもできます。
<style> 要素を添付する手法は、宣言的でありたい場合や、保有するスタイルがいくつかある場合、異なるコンポーネント間でスタイルを共有する必要がない場合に最適です。
シャドウ DOM によってカプセル化が提供されなければ、カスタム要素は非常に壊れやすいものになってしまいます。 ページで実行する JavaScript や CSS によって、カスタム要素の動作やレイアウトが誤って壊れてしまうことが簡単に起こり得ます。 カスタム要素を開発する立場では、カスタム要素内で適用されるセレクターが、カスタム要素を使用することを選んだページで適用されるセレクターと競合しているかどうかを知ることはできません。
カスタム要素は、ベースの HTMLElement または HTMLParagraphElement などの組み込みの HTML 要素を拡張するクラスとして実装されます。通常、カスタム要素自体がシャドウホストとなり、その要素がルートの下に複数の要素を作成し、要素の内部実装を提供します。
次の例では、単一色で塗りつぶされた円を描画するカスタム要素 <filled-circle> を作成します。
カスタム要素の実装のさまざまな側面を示す例については、[カスタム要素のガイド]を参照してください。
This page was last modified on 2025年11月9日 by MDN contributors.
Your blueprint for a better internet.
Visit Mozilla Corporation’s not-for-profit parent, the Mozilla Foundation.
Portions of this content are ©1998–2026 by individual mozilla.org contributors. Content available under a Creative Commons license.