Shadow DOM

Shadow DOM は、Web コンポーネントの内部ドキュメントオブジェクトモデル (DOM) 構造をカプセル化する標準です。DOM をカプセル化すると、開発者はコンポーネントを共有し、コンポーネントが任意の HTML、CSS、JavaScript によって操作されるのを防ぐことができます。内部 DOM 構造は、シャドウツリーと呼ばれます。シャドウツリーは、CSS、イベント、および DOM の操作方法に影響します。

すべてのブラウザに Shadow DOM が実装されているわけではないため、LWC では、Lightning Experience および Experience Cloud に合成 Shadow ポリフィルが使用されます。ポリフィルとは、機能が Web ブラウザで動作できるようにするコードのことです。

Explaining the Shadow DOM (Shadow DOM の説明)

Lightning Out など、Lightning Experience や Experience Cloud の外部で LWC を使用する場合、LWC はネイティブ Shadow モードでレンダリングされます。「Salesforce Platform でのコンパイル時の違い」を参照してください。

シャドウツリーを理解するため、いくつかのマークアップを見てみましょう。次のマークアップには、c-todo-appc-todo-item の 2 つの Lightning Web コンポーネントが記述されています。#shadow-root ドキュメントフラグメントでは、DOM とシャドウツリー間の境界が定義されます。シャドウルートの下の要素がシャドウツリーに含まれます。

これらの各エリアでシャドウツリーを操作する方法を見てみましょう。

CSS

親コンポーネントで定義された CSS スタイルは、子に継承されません。この例の場合、todoApp.css スタイルシートに定義された p スタイルで、c-todo-item コンポーネントの p 要素のスタイルが設定されることはありません。このスタイルは、シャドウツリーに到達しないためです。「CSS」を参照してください。

イベント

コンポーネントの内部の詳細が公開されることを防止するため、イベントが上に伝達してシャドウ境界を横断した場合は、いくつかのプロパティ値がリスナーの範囲に応じて変更されます。「イベント対象変更」を参照してください。

要素へのアクセス

シャドウツリーの要素には、従来の DOM クエリ方法ではアクセスできません。コードで document または document.body を使用して Lightning Web コンポーネントのシャドウツリーにアクセスすることはできません。たとえば、コードで document.querySelector() をコールして Lightning Web コンポーネントのシャドウツリーのノードを選択することはできません。Lightning Web コンポーネントは、コンポーネント自体のシャドウツリーにアクセスするために、this.template.querySelector() をコールします。「コンポーネントが所有する要素へのアクセス」を参照してください。

スロットへのアクセス

スロットは、親コンポーネントがコンポーネントの本体に渡すマークアップのプレースホルダです。スロットを介してコンポーネントに渡される DOM 要素は、コンポーネントによって所有されないため、コンポーネントのシャドウツリーには含まれません。スロットを介して渡される DOM 要素にアクセスするには、this.querySelector() をコールします。コンポーネントはこれらの要素を所有しないため、template は使用しないでください。「スロットにマークアップを渡す」を参照してください。

コンポーネントのテスト

「変更される可能性がある DOM 検査テスト」を参照してください。

Saleforce 開発者エバンジェリストの Alba Rivas による Shadow DOM の説明をご覧ください。

Lightning Locker を使用している組織では、コンポーネントのシャドウツリーの内部にアクセスする場合、次の DOM API は使用しないでください。これらの DOM API を使用してコンポーネントのシャドウツリー内部にアクセスするサードパーティ JavaScript ライブラリを使用している場合は、ライブラリ作成者と協力して問題を登録し、修正してください。

  • Document.prototype.getElementById
  • Document.prototype.querySelector
  • Document.prototype.querySelectorAll
  • Document.prototype.getElementsByClassName
  • Document.prototype.getElementsByTagName
  • Document.prototype.getElementsByTagNameNS
  • Document.prototype.getElementsByName
  • document.body.querySelector
  • document.body.querySelectorAll
  • document.body.getElementsByClassName
  • document.body.getElementsByTagName
  • document.body.getElementsByTagNameNS

Lightning Locker では、これらの API をブロックすることにより、Lightning Web コンポーネント間の Shadow DOM カプセル化を壊すことは防止されています。ただし、Aura コンポーネントのバージョン 39.0 以降では、Lightning Locker がコンポーネントレベルで無効になっているため、Aura コンポーネントのコードは失敗します。

これらの API は Lightning Web セキュリティ (LWS) による制限を受けません。LWS では、すべてのコンポーネントについて ShadowRoot の mode プロパティに closed の値を設定することにより、Shadow DOM のカプセル化を壊すことが防止されています。

Shadow DOM ポリフィルには、MutationObserver インターフェースへのパッチが含まれます。MutationObserver を使用して DOM ツリーの変化を監視している場合、それを切断します。そのようにしないと、メモリリークが発生します。コンポーネントでは、各自のテンプレートの変異のみを監視できます。シャドウツリーまたは他のカスタム要素内の変異を監視することはできません。