🚀

Shadow DOM の仕様について

2025/02/17に公開
4

Shadow DOM の概要

Shadow DOM とは、Web コンポーネントにおける「カプセル化された DOM」のことを指します。通常の DOM はグローバルにアクセス可能ですが、Shadow DOM を利用すると、内部構造を外部から隠すことができます。この特性により、次のようなメリットが得られます。

✅ スタイルやスクリプトの競合を防ぐ
✅ コンポーネントの再利用性を向上させる

https://developer.mozilla.org/ja/docs/Web/API/Web_components/Using_shadow_DOM

Shadow DOM には open と closed の 2 種類のモードがあります。これらは、外部からのアクセス制御の度合いに影響を与えます。

open モード

open モードでは、Shadow DOM が外部からアクセス可能になります。shadowRoot プロパティを介して操作できるため、拡張性が求められるコンポーネントに適しています。

特徴:

  • shadowRoot プロパティが公開され、外部から DOM にアクセス可能
  • 他のスクリプトから Shadow DOM 内部を変更できる
const shadowHost = document.querySelector('#shadow-host');
const shadowRoot = shadowHost.attachShadow({ mode: 'open' });

shadowRoot.innerHTML = `<p>Shadow DOM</p>`;

console.log(shadowHost.shadowRoot == shadowRoot); // true - documentからアクセスできる
<template>要素を使う場合
<div class="shadow-host">
  <template shadowrootmode="open">
    <p>Shadow DOM</p>
  </template>
</div>
const shadowHost = document.querySelector(".shadow-host");
const shadowRoot = shadowHost.shadowRoot;

console.log(shadowRoot.innerText);

closed モード

このモードでは、shadowRoot プロパティが null を返し、外部からのアクセスができなくなります。これにより、意図しないスクリプトによる改変を防ぐことができます。

const shadowHost = document.querySelector('#shadow-host');
const shadowRoot = shadowHost.attachShadow({ mode: 'closed' });

shadowRoot.innerHTML = `<p>Shadow DOM</p>`;

console.log(shadowHost.shadowRoot); // null が返される

console.log(shadowRoot); // shadowRootという変数からのみ、操作可能
<template>要素を使う場合
<div class="shadow-host">
  <template shadowrootmode="closed">
    <p>Shadow DOM</p>
  </template>
</div>
// 外部からアクセスできなくなるので、安全

Shadow DOM の基本的な使い方

Shadow DOM に CSS を適用する方法

Shadow DOM 内部のスタイルは、通常の CSS とは異なり、外部のスタイルの影響を受けません。適用する方法は大きく分けて 2 つあります。

const host = document.querySelector("#host");
const shadow = host.attachShadow({ mode: "open" });

const sheet = new CSSStyleSheet();
sheet.replaceSync("span { color: red; border: 2px dotted black;}");

shadow.adoptedStyleSheets = [sheet];

const span = document.createElement("span");
span.textContent = "I'm in the shadow DOM";
shadow.appendChild(span);

Shadow DOM はセキュリティ機能ではない

Shadow DOM はセキュリティ機能ではありません。これは、CSS のスコープを設定し、DOM ツリーをコンポーネントの中に隠すための軽量なツールです。真のセキュリティ境界が必要な場合は、<iframe> を使用します。
https://web.dev/articles/shadowdom-v1?hl=ja#faq

簡易的なiframe sandboxのコードは、こちら に置いておきます

https://developer.mozilla.org/ja/docs/Web/HTML/Element/iframe#sandbox

参考文献

https://developer.mozilla.org/ja/docs/Web/API/ShadowRoot
https://developer.mozilla.org/ja/docs/Web/HTML/Element/template
https://developer.mozilla.org/ja/docs/Web/API/EventTarget/addEventListener
https://developer.mozilla.org/ja/docs/Web/API/Event/stopPropagation
https://zenn.dev/cybozu_frontend/articles/20240301_whats-new-in-browser-firefox-123
https://web.dev/articles/shadowdom-v1?hl=ja#faq

Discussion

SatoooonSatoooon

Shadow DOM はセキュリティ機能として設計されていません。Shadow DOMの外部/内部間で定義されたJSやCSSの影響を互いに受けないようにし、コンポーネントのカプセル化を実現するための機能です。

そのため、「基本的な使い方」で例示したようなclosedモードを利用して機密情報を保護する目的には適していません。

Shadow DOM is not a security feature. It's a lightweight tool for scoping CSS and hiding away DOM trees in component. If you want a true security boundary, use an <iframe>.
https://web.dev/articles/shadowdom-v1#faq