言語
日本語
English

Caution

お使いのブラウザはJavaScriptが無効になっております。
当サイトでは検索などの処理にJavaScriptを使用しています。
より快適にご利用頂くため、JavaScriptを有効にしたうえで当サイトを閲覧することをお勧めいたします。

  1. トップページ
  2. HTML辞典
  3. <template> / <slot>

<template> / <slot>

対応: HTML Living Standard(2019〜)

『template』はブラウザに描画されない再利用可能なHTMLの雛形を定義する要素で、『slot』はWeb Componentsでカスタム要素の内側に外部からコンテンツを差し込む挿入口を定義するために使用します。Web Componentsは再利用可能なカスタムHTML要素を作る仕組みです。Shadow DOMはコンポーネント内部のHTMLとCSSを外部から隔離します。

構文

<!-- template: 描画されないHTMLの雛形 -->
<template id="card-template">
  <div class="card">
    <h2 class="card-title"></h2>
    <p class="card-body"></p>
  </div>
</template>

<!-- slot: Web Componentsの挿入口(Shadow DOM内で使用) -->
<template id="my-card-template">
  <style>
    .card { border: 1px solid #ccc; padding: 16px; }
  </style>
  <div class="card">
    <!-- 名前なしスロット(デフォルトスロット) -->
    <slot></slot>
    <!-- 名前付きスロット -->
    <slot name="footer"></slot>
  </div>
</template>

属性・プロパティ一覧

属性 / プロパティ概要
template#contentテンプレート要素の内容にアクセスするためのプロパティです。『DocumentFragment』として取得できます。
cloneNode(true)テンプレートのコンテンツを複製するメソッドです。『true』を渡すと子要素も含めてディープコピーします。
slot(属性)カスタム要素の子要素に指定する属性で、どのスロットに挿入するかを名前で指定します。
slot nameShadow DOM内の『slot』要素に付ける名前です。対応するカスタム要素の子要素が差し込まれます。

サンプルコード

sample_template_slot.html
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <style>
    .card {
      border: 1px solid #ddd;
      border-radius: 8px;
      padding: 16px;
      margin: 8px;
      max-width: 300px;
    }
    .card-title { font-weight: bold; font-size: 1.1em; margin: 0 0 8px; }
    .card-body  { color: #555; margin: 0; }
  </style>
</head>
<body>

  <!-- template要素: ブラウザには描画されない -->
  <template id="card-template">
    <div class="card">
      <p class="card-title"></p>
      <p class="card-body"></p>
    </div>
  </template>

  <div id="container"></div>

  <script>
    // カードのデータ
    const cards = [
      { title: 'HTML',       body: 'Webページの構造を作る言語です。' },
      { title: 'CSS',        body: 'Webページのデザインを担当します。' },
      { title: 'JavaScript', body: 'Webページに動きを追加します。' },
    ];

    const template = document.getElementById('card-template');
    const container = document.getElementById('container');

    cards.forEach(({ title, body }) => {
      // テンプレートを複製してデータを書き込む
      const clone = template.content.cloneNode(true);
      clone.querySelector('.card-title').textContent = title;
      clone.querySelector('.card-body').textContent  = body;
      container.appendChild(clone);
    });
  </script>

</body>
</html>

実行結果

ページを開くとJavaScriptによってテンプレートが3回複製され、HTML・CSS・JavaScriptの3枚のカードが縦に並んで表示されます。テンプレートそのものはHTMLソースにあっても画面には表示されません。

サンプルページはこちら

概要

『template』要素は、ページ読み込み時にはブラウザに描画されず、CSSも適用されず、スクリプトも実行されないHTMLの「雛形」です。JavaScriptで複製(cloneNode)してDOMに追加することで初めて画面に表示されます。同じ構造を繰り返し生成する場合(リスト・カード・テーブル行など)に、innerHTML で文字列からHTMLを生成するよりも安全かつ効率的です。innerHTML にユーザー入力の文字列を渡すとXSSの危険がありますが、『template』を使ったcloneNode + textContentによる値の設定はXSSが発生しません。

『slot』はWeb Components(カスタム要素 + Shadow DOM)の仕組みの一部で、カスタム要素の利用者が外部から内容を差し込める「穴」を定義します。名前なしスロット(デフォルトスロット)はカスタム要素のすべての子要素を受け取り、『name』属性を付けた名前付きスロットは『slot="名前"』属性を持つ特定の子要素だけを受け取ります。

Web Componentsは独立したカプセル化されたUIコンポーネントをHTMLとJavaScriptで作成する仕様です。ReactやVueなどのフレームワークに依存しない、ブラウザネイティブのコンポーネント化の仕組みとして注目されています。ただし、Shadow DOMの仕様はやや複雑なため、まずは『template』要素によるシンプルなHTML雛形の活用から始めることをおすすめします。関連する要素として『script / noscript』も参照してください。

対応ブラウザ

Chrome Chrome
26 以降
25 以前 ×
Firefox Firefox
22 以降
21 以前 ×
Safari Safari
8 以降
7 以前 ×
Edge Edge
13 以降
IE IE
非対応 ×
Opera Opera
15 以降
14 以前 ×
iOS Safari iOS Safari
8 以降
7 以前 ×
Android Android Browser
4.4 以降
4 以前 ×
Chrome Android Chrome Android
最新版
デスクトップ版と同等の対応です
Firefox Android Firefox Android
最新版
デスクトップ版と同等の対応です

※ バージョン情報は MDN に基づいています。

実践的なtemplateの活用

『<template>』はJavaScriptで繰り返し同じHTML構造を生成する際に特に役立ちます。

<!-- カードのテンプレート定義 -->
<template id="card-template">
  <div class="card">
    <img class="card-img" src="" alt="">
    <div class="card-body">
      <h3 class="card-title"></h3>
      <p class="card-text"></p>
    </div>
  </div>
</template>

<!-- カードを表示するコンテナ -->
<div id="card-container"></div>

<script>
  var items = [
    { img: "cat.jpg", alt: "猫の写真", title: "猫カフェ訪問", text: "かわいい猫たちと触れ合いました" },
    { img: "dog.jpg", alt: "犬の写真", title: "ドッグラン体験", text: "元気な犬たちと遊びました" }
  ];

  var tmpl = document.getElementById('card-template');
  var container = document.getElementById('card-container');

  items.forEach(function(item) {
    // templateの内容を複製する(importNodeでDeep Cloneする)
    var clone = document.importNode(tmpl.content, true);
    clone.querySelector('.card-img').src = item.img;
    clone.querySelector('.card-img').alt = item.alt;
    clone.querySelector('.card-title').textContent = item.title;
    clone.querySelector('.card-text').textContent = item.text;
    container.appendChild(clone);
  });
</script>

JavaScriptで文字列結合してHTMLを生成する方法(innerHTML)と比べ、『<template>』を使うほうがXSSのリスクが低く、構造が分かりやすいという利点があります。Webコンポーネント(Custom Elements)でも『<template>』と『<slot>』を組み合わせて使います。

記事の間違いや著作権の侵害等ございましたらお手数ですがまでご連絡頂ければ幸いです。