template要素の使い方
HTMLのtemplate要素は、あとで使うHTMLのひな形をページの中に用意しておくための要素です。template自身は画面に表示されず、必要になったときに中身をコピーしてページへ追加します。
先に結論
templateは、同じ形のカードや行を何度も作るときに便利です。中身はtemplate.contentというDocumentFragmentに入り、cloneNode(true)でコピーしてから表示します。
ひな形を置いただけでは表示されません。コピーした内容をappendなどでページへ追加する処理が必要です。
最小の例
<template id="user-card-template">
<article>
<h2 data-name></h2>
<p data-role></p>
</article>
</template>
<section id="users"></section>
<script>
const template = document.querySelector('#user-card-template');
const card = template.content.cloneNode(true);
card.querySelector('[data-name]').textContent = 'Aki';
card.querySelector('[data-role]').textContent = 'デザイナー';
document.querySelector('#users').append(card);
</script>
最初にtemplateを取得し、contentを深くコピーします。コピーした断片に文字を入れてからページへ追加すると、カードが表示されます。
templateの中身はどこにある?
templateの中に書いた要素は、通常の親子関係でtemplateの子になるわけではありません。ひな形の中身はtemplate.contentから取得します。
const template = document.querySelector('#user-card-template');
template.childNodes.length; // 0
template.content.childNodes.length; // 1
const copy = template.content.cloneNode(true);
document.querySelector('#users').append(copy);
trueを渡すと、見出しや説明文などの子孫も一緒にコピーされます。コピーしたDocumentFragmentを追加すると、その中の要素がページのDOMになります。
実際にカードを追加する
ボタンを押すと、同じひな形からカードを追加します。
まだカードはありません。
この例では、画面に置かれているのはボタンと空のリストです。templateの内容は、ボタンを押してコピーを追加したときに初めて表示されます。
データを入れるときの注意
ユーザー名や外部データをひな形へ入れるときは、通常の文字列ならtextContentを使います。HTMLとして解釈させる必要がない文字列をinnerHTMLへ入れると、意図しない要素やスクリプトを作る危険があります。
- 繰り返し使うひな形には、役割が分かる
idやdata-*属性を付ける。 - 同じひな形を複数回追加する場合、固定した
idを重複させない。 - 表示に必要な見出し、ラベル、説明は、コピー後のDOMにも残るようにする。
- ひな形を使うJavaScriptが失敗した場合に、必要な情報が完全に消えないか確認する。
templateと非表示の要素の違い
display: noneにした要素は、通常のDOMとして存在しながら、表示やアクセシビリティの扱いが変わります。一方、templateの中身は、そもそも通常のページの子要素として表示される状態ではありません。あとでコピーするひな形を保存したいときにtemplateを使います。
Declarative Shadow DOMについて
templateには、shadowrootmode属性を使ってDeclarative Shadow DOMを宣言する高度な使い方もあります。これは通常のカード作成より複雑で、Shadow DOMの境界、slot、focus、アクセシビリティを一緒に確認する必要があります。
<my-card>
<template shadowrootmode="open">
<slot></slot>
</template>
カードの本文
</my-card>
まずはcontent.cloneNode(true)を使う通常のひな形から理解し、Shadow DOMの仕様や実装差まで知りたいときはAtlasを参照してください。
よくある間違い
templateを書いただけで、画面に中身が表示されると思う。template.querySelector()で、ひな形の中の要素を直接探せると思う。cloneNode(true)を使わず、同じノードを何度も追加できると思う。- コピーした内容に同じ
idが増え、ラベルやリンクの参照が壊れる。 - ひな形が入力値を安全にしてくれる、または
templateがサニタイザーになると思う。
Atlasで詳しく確認する
Template Contents、DocumentFragment、parser、Declarative Shadow DOM、Accessibility、ブラウザー実装の確認条件まで詳しく知りたい場合は、Yugien Atlasのtemplate要素を参照してください。