2.

HTML template要素の使い方|content・cloneNodeとWeb Components

編集
この記事の要点
  • <template> は HTML 内に「描画されないテンプレート断片」を埋め込む要素
  • 中身はパースはされるが描画されない。スクリプト・画像も読み込まれない
  • JS から template.content.cloneNode(true)複製して使う
  • クライアント側テンプレートWeb Components(Shadow DOM)で多用される
  • innerHTML 連結より安全・高速(DOM ツリー化済み、再パース不要)

template要素とは

<template> は HTML5 で追加された要素で、「ページには描画したくないが、JS から取り出して使いたい HTML 断片」を埋め込むためのものです。中身はパース時に DOM ツリー化されますが、レンダリングされず、スクリプトも実行されず、画像も読み込まれません。一覧表示の繰り返しブロックや、Web Components の Shadow DOM のテンプレートとして使われます。

基本構文

<template id="card-template">
  <div class="card">
    <h3 class="title"></h3>
    <p class="body"></p>
    <button class="more">詳しく</button>
  </div>
</template>

<div id="list"></div>

<script>
  const tpl  = document.getElementById('card-template');
  const list = document.getElementById('list');

  const data = [
    { title: '記事A', body: '本文A' },
    { title: '記事B', body: '本文B' },
  ];

  for (const item of data) {
    const node = tpl.content.cloneNode(true);  // 深いコピー
    node.querySelector('.title').textContent = item.title;
    node.querySelector('.body').textContent  = item.body;
    list.appendChild(node);
  }
</script>

特徴

  • 中身は document fragment として保持される(template.content
  • 描画されない(display:none を書く必要すらない)
  • 中の <img><script>読み込まれない・実行されない
  • HTML として不正な入れ子も書ける<tr> 単体など)
  • JS で複製してから DOM に挿入するのが基本パターン

innerHTML との比較

項目innerHTML で連結<template> + cloneNode
パース毎回 HTML 文字列をパース初回 1 回だけ
速度遅い速い
XSS注意必要(文字列連結で混入しやすい)safer(textContent で代入できる)
イベント後から再付与テンプレート側に書ける(複製後付与)
可読性JS 内の文字列が肥大HTML と JS が分離

tr / td など不正な入れ子も書ける

通常の HTML では <table> の外に <tr> を書くと自動的に取り除かれてしまいますが、<template> の中であればテーブル断片だけを保持できます。

<template id="row-template">
  <tr>
    <td class="name"></td>
    <td class="email"></td>
  </tr>
</template>

<table>
  <tbody id="tbody"></tbody>
</table>

Web Components との組み合わせ

Custom Elements の Shadow DOM を初期化するときに <template> がよく使われます。

const tpl = document.createElement('template');
tpl.innerHTML = `
  <style>
    .greet { color: tomato; font-weight: bold; }
  </style>
  <p class="greet">Hello, <slot name="name">World</slot>!</p>
`;

class HelloElement extends HTMLElement {
  constructor() {
    super();
    this.attachShadow({ mode: 'open' })
        .appendChild(tpl.content.cloneNode(true));
  }
}
customElements.define('x-hello', HelloElement);

<template> と <slot> の違い

  • <template>: ページに描画されないテンプレート定義。JS から取り出して使う
  • <slot>: Shadow DOM 内で外部から挿入される箇所を示す。Web Components の差し込み穴

よくある落とし穴

  • tpl.cloneNode(true) をすると<template> ごとコピーされる — 使いたいのは中身なので tpl.content.cloneNode(true) を使う
  • 同じ要素を直接 appendChild すると、最後の 1 つだけ DOM に移動してしまう(複製しないと使い回せない)
  • 中身は描画されないので CSS のセレクタも当たらない(複製後に当たる)
  • IE11 は未対応(モダンブラウザは全対応)

関連

編集
Post Share
子ページ

子ページはありません

同階層のページ
  1. figure要素
  2. template要素
  3. figcaption要素で図に説明を付ける
  4. canvas要素
  5. iframe要素
  6. script要素
  7. noscript要素

最近更新/作成されたページ