<template>: コンテンツテンプレート要素
Baseline Widely available
This feature is well established and works across many devices and browser versions. It’s been available across browsers since November 2015.
<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
が既定値です。 shadowrootserializable
Experimental-
この要素を使用して作成した
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 Standard # the-template-element |
ブラウザーの互換性
BCD tables only load in the browser
関連情報
part
およびexportparts
属性<slot>
要素:host
、:host()
、:host-context()
擬似クラス::part
、::slotted
擬似要素ShadowRoot
インターフェイス- テンプレートとスロットの使用
- CSS スコープ化 モジュール
- 宣言的シャドウ DOM (HTML による) (シャドウ DOM の使用)
- Declarative shadow DOM (developer.chrome.com, 2023)