<template>: コンテンツテンプレート要素
Baseline
Widely available
*
This feature is well established and works across many devices and browser versions. It’s been available across browsers since 2015年11月.
* Some parts of this feature may have varying levels of support.
<template> は HTML の要素で、HTML フラグメントを保持し、後で JavaScript を使用して使用したり、シャドウ DOM の中に即座に生成したりするためのメカニズムとして機能します。
属性
この要素にはグローバル属性があります。
shadowrootmode-
親要素のシャドウルートを生成します。 これは
Element.attachShadow()メソッドの宣言版で、同じ enumerated 値を受け入れます。メモ: HTML パーサーは、この属性が設定されているノードの最初の
<template>に対して、DOM にShadowRootオブジェクトを作成します。 この属性が設定されていない場合、または許可された値が設定されていない場合、あるいはShadowRootが既に同じ親に宣言的に作成されている場合は、HTMLTemplateElementが作成されます。HTMLTemplateElementは、HTMLTemplateElement.shadowRootModeを設定したりすることで、解釈後にシャドウルートに変更することはできません。メモ: 古いチュートリアルや例では、Chrome 90-110 で対応していた非標準の
shadowroot属性が見つかるかもしれません。この属性は削除され、標準のshadowrootmode属性に置き換えられています。 shadowrootclonable-
この要素を使用して作成した
ShadowRootのclonableプロパティの値をtrueに設定します。 設定されている場合、シャドウホスト(この<template>の親要素)の複製をNode.cloneNode()またはDocument.importNode()で作成すると、コピーにシャドウルートが含まれます。 shadowrootdelegatesfocus-
この要素を使用して作成した
ShadowRootのdelegatesFocusプロパティの値をtrueに設定します。 これが設定されていて、シャドウツリー内のフォーカス可能でない要素が選択されている場合、フォーカスはツリー内の最初のフォーカス可能な要素に譲られます。 この値はfalseが既定値です。 shadowrootserializableExperimental-
この要素を使用して作成した
ShadowRootのserializableプロパティの値をtrueに設定します。 設定されている場合、シャドウルートはElement.getHTML()またはShadowRoot.getHTML()メソッドを、options.serializableShadowRoots引数をtrueに設定して呼び出すことでシリアライズされます。 この値はfalseが既定値です。
使用上のメモ
<template> 要素の主な用途は 2 つあります。
テンプレート文書フラグメント
既定では、要素のコンテンツはレンダリングされません。
対応する HTMLTemplateElement インターフェイスは標準で content プロパティを含みます(同等の content/markup 属性はありません)。この content プロパティは読み取り専用で、テンプレートが表す DOM サブツリーを格納する DocumentFragment を保持します。
このフラグメントは cloneNode メソッドで複製し、DOM に挿入することができます。
content プロパティを使用するときは、返値の DocumentFragment が予期せぬ挙動を示すことがあることに注意が必要です。
詳細は下記の DocumentFragment の落とし穴を避ける節を参照してください。
宣言的シャドウ DOM
もし <template> 要素が shadowrootmode 属性の値 open または closed を格納すると、HTML パーサーは直ちにシャドウ DOM を生成します。その要素は ShadowRoot でラップされたコンテンツによって DOM 内で置き換えられ、親要素に装着されます。
これは Element.attachShadow() を呼び出して要素にシャドウルートを付けるのと宣言的に等価です。
要素が shadowrootmode に他の値を示す場合、または shadowrootmode 属性を持たない場合、パーサは HTMLTemplateElement を生成します。
同様に、宣言的シャドウルートが複数ある場合、最初のシャドウルートのみが ShadowRoot で置き換えられ、それ以降は HTMLTemplateElement オブジェクトとして解釈できます。
例
>表の行を生成
まず、HTML 部分の例から始めましょう。
<table id="producttable">
<thead>
<tr>
<td>UPC_Code</td>
<td>Product_Name</td>
</tr>
</thead>
<tbody>
<!-- existing data could optionally be included here -->
</tbody>
</table>
<template id="productrow">
<tr>
<td class="record"></td>
<td></td>
</tr>
</template>
まず、JavaScript コードを使用して後からコンテンツを挿入するための表を作ります。次に、1 行分を表す HTML 断片の構造が書かれたテンプレートが続きます。
表が生成され、テンプレートが定義されました。 JavaScript を使って、テンプレートを基に構築される各行を表に挿入します。
// templete 要素の content 属性の有無を確認することで、
// ブラウザーが HTML の template 要素に対応しているかテストします。
if ("content" in document.createElement("template")) {
// 既存の HTML tbody と template の行を使って
// table をインスタンス生成します。
const tbody = document.querySelector("tbody");
const template = document.querySelector("#productrow");
// 新しい行を複製して表に挿入します。
const clone = template.content.cloneNode(true);
let td = clone.querySelectorAll("td");
td[0].textContent = "1235646565";
td[1].textContent = "Stuff";
tbody.appendChild(clone);
// 新しい行を複製して表に挿入します。
const clone2 = template.content.cloneNode(true);
td = clone2.querySelectorAll("td");
td[0].textContent = "0384928528";
td[1].textContent = "Acme Kidney Beans 2";
tbody.appendChild(clone2);
} else {
// HTML の template 要素に対応していないので
// 表に行を追加するほかの方法を探します。
}
結果として、 JavaScript を通して、新しい行が追加された HTML の表ができます。
宣言的シャドウ DOM の実装
この例では、マークアップの始めに非表示で対応する警告を記載しています。この警告は後でブラウザーの shadowrootmode 属性に対応していない場合に JavaScript で表示するように設定します。次の記事には 2 つの <article> 要素があり、それぞれ異なる振る舞いをする <style> 要素を含んでいます。最初の <style> 要素は文書全体に対してグローバルです。2 つ目は shadowrootmode 属性が存在するため、<template> 要素の代わりに生成されたシャドウルートにスコープされます。
<p hidden>
⛔ Your browser doesn't support <code>shadowrootmode</code> attribute yet.
</p>
<article>
<style>
p {
padding: 8px;
background-color: wheat;
}
</style>
<p>I'm in the DOM.</p>
</article>
<article>
<template shadowrootmode="open">
<style>
p {
padding: 8px;
background-color: plum;
}
</style>
<p>I'm in the shadow DOM.</p>
</template>
</article>
const isShadowRootModeSupported =
HTMLTemplateElement.prototype.hasOwnProperty("shadowRootMode");
document
.querySelector("p[hidden]")
.toggleAttribute("hidden", isShadowRootModeSupported);
フォーカスを譲渡を伴う宣言的シャドウ DOM
この例では、shadowrootdelegatesfocus を宣言的に作成したシャドウルートに適用し、フォーカスにどのような効果があるかを示します。
このコードでは、最初に <template> 要素に shadowrootmode 属性を用いて、<div> 要素の中にシャドウルートを宣言します。
これにより、テキストを格納したフォーカスできない <div> と、フォーカスできる <input> 要素の両方が表示されます。
また、:focus を持つ要素を青にスタイル設定し、ホスト要素の通常のスタイル設定を設定するには CSS を使用します。
<div>
<template shadowrootmode="open">
<style>
:host {
display: block;
border: 1px dotted black;
padding: 10px;
margin: 10px;
}
:focus {
outline: 2px solid blue;
}
</style>
<div>Clickable Shadow DOM text</div>
<input type="text" placeholder="Input inside Shadow DOM" />
</template>
</div>
2 つ目のコードブロックは、shadowrootdelegatesfocus 属性を設定している以外は同じです。この属性は、ツリー内のフォーカス可能でない要素が選択された場合に、ツリー内の最初のフォーカス可能な要素にフォーカスを譲ったものです。
<div>
<template shadowrootmode="open" shadowrootdelegatesfocus>
<style>
:host {
display: block;
border: 1px dotted black;
padding: 10px;
margin: 10px;
}
:focus {
outline: 2px solid blue;
}
</style>
<div>Clickable Shadow DOM text</div>
<input type="text" placeholder="Input inside Shadow DOM" />
</template>
</div>
最後に、以下の CSS を使用して、親要素である <div> にフォーカスがあるときに緑黄色の枠線を適用します。
div:focus {
border: 2px solid red;
}
その結果を下記に示します。
HTML は最初にレンダリングされるとき、最初の画像に示すように要素にはスタイル設定がありません。
shadowrootdelegatesfocus が設定されていないシャドウルートでは、<input> 以外の場所をクリックしてもフォーカスは変わりません(<input> 要素を選択すると 2 つ目の画像のようになります)。

shadowrootdelegatesfocus を設定したシャドウルートでは、テキスト(フォーカスできない)をクリックすると、<input> 要素が選択されます。
これは下記に示すように親要素もフォーカスされます。

DocumentFragment の落とし穴の回避
DocumentFragment の値が渡されると、Node.appendChild や同様のメソッドはその値の子ノードだけを対象とするノードに移動させます。したがって、イベントハンドラーは DocumentFragment 自体ではなく、DocumentFragment の子ノードに設定することが推奨されます。
以下の HTML および JavaScript を考えてみてください。
HTML
<div id="container"></div>
<template id="template">
<div>クリックしてください</div>
</template>
JavaScript
const container = document.getElementById("container");
const template = document.getElementById("template");
function clickHandler(event) {
event.target.append(" — この div がクリックされました");
}
const firstClone = template.content.cloneNode(true);
firstClone.addEventListener("click", clickHandler);
container.appendChild(firstClone);
const secondClone = template.content.cloneNode(true);
secondClone.children[0].addEventListener("click", clickHandler);
container.appendChild(secondClone);
結果
firstClone は DocumentFragment なので、appendChild が呼び出されたときに container に追加されるのはその子ノードだけで、firstClone のイベントハンドラーはコピーされません。一方、secondClone は最初の子ノードにイベントハンドラーが追加されているため、appendChild が呼び出されるとイベントハンドラーがコピーされ、クリックすると期待通りに動作します。
技術的概要
| コンテンツカテゴリー | メタデータコンテンツ, フローコンテンツ, 記述コンテンツ, スクリプト対応要素 |
|---|---|
| 許可されている内容 | 制限なし |
| タグの省略 | なし。開始タグと終了タグの両方が必須です。 |
| 許可されている親要素 |
メタデータコンテンツ,
記述コンテンツ,
スクリプト対応要素
を受け付けるすべての要素。また、 span 属性を持たない <colgroup> 要素の子になることもできます。
|
| 暗黙の ARIA ロール | 対応するロールなし |
| 許可されている ARIA ロール | 許可されている role なし |
| DOM インターフェイス | HTMLTemplateElement |
仕様書
| Specification |
|---|
| HTML> # the-template-element> |
ブラウザーの互換性
Loading…
関連情報
partおよびexportparts属性<slot>要素:host、:host()、:host-context()擬似クラス::part、::slotted擬似要素ShadowRootインターフェイス- テンプレートとスロットの使用
- CSS スコープ化 モジュール
- 宣言的シャドウ DOM (HTML による) (シャドウ DOM の使用)
- Declarative shadow DOM (developer.chrome.com, 2023)