HTML5 template: шаблоны разметки без рендера и лишнего JavaScript
Если вам нужно многократно добавлять на страницу одинаковые блоки — карточки товаров, сообщения чата, пункты списка, строки таблицы, — не обязательно собирать HTML длинными строками в JavaScript. Для этого в HTML5 есть тег <template>. Он хранит разметку в документе, но браузер не рендерит её до тех пор, пока вы сами не скопируете содержимое шаблона и не вставите его в нужное место.
Эта статья оптимизирована под запрос «HTML template пример» и показывает практический сценарий: создадим список товаров на основе HTML-шаблона.
Что делает тег template в HTML5
<template> — это контейнер для «спящей» разметки. Всё, что находится внутри него:
template.content в JavaScript.Базовый пример выглядит так:
<template id="message-template">
<article class="message">
<h3 class="message__title"></h3>
<p class="message__text"></p>
</article>
</template>
Сам по себе этот код ничего не покажет пользователю. Чтобы вывести блок, нужно клонировать содержимое шаблона.
Практический пример: карточки товаров из template
Представим, что у нас есть массив товаров, и мы хотим вывести карточки в каталог. Сначала подготовим HTML-разметку: контейнер для результата и шаблон одной карточки.
<section class="catalog" aria-label="Каталог товаров">
<div class="catalog__grid" id="product-list"></div>
</section>
<template id="product-card-template">
<article class="product-card">
<img class="product-card__image" src="" alt="" width="300" height="200">
<h3 class="product-card__title"></h3>
<p class="product-card__price"></p>
<button class="product-card__button" type="button">В корзину</button>
</article>
</template>
Теперь добавим JavaScript, который берёт шаблон, клонирует его и заполняет данными.
const products = [
{
title: 'HTML и CSS: стартовый набор',
price: 990,
image: 'images/html-css.jpg'
},
{
title: 'JavaScript для верстальщика',
price: 1490,
image: 'images/js.jpg'
},
{
title: 'Адаптивная вёрстка',
price: 1290,
image: 'images/adaptive.jpg'
}
];
const list = document.querySelector('#product-list');
const template = document.querySelector('#product-card-template');
products.forEach((product) => {
const card = template.content.cloneNode(true);
const image = card.querySelector('.product-card__image');
const title = card.querySelector('.product-card__title');
const price = card.querySelector('.product-card__price');
image.src = product.image;
image.alt = product.title;
title.textContent = product.title;
price.textContent = `${product.price} ₽`;
list.append(card);
});
Ключевая строка здесь — template.content.cloneNode(true). Метод cloneNode(true) создаёт глубокую копию, то есть копирует не только сам контейнер, но и все вложенные элементы.
Почему template лучше, чем сборка HTML строками
Новички часто пишут так:
list.innerHTML += `
<article class="product-card">
<h3>${product.title}</h3>
<p>${product.price} ₽</p>
</article>
`;
Такой подход кажется коротким, но у него есть минусы:
innerHTML += браузер может пересоздавать уже существующие узлы;С <template> структура остаётся в HTML, а JavaScript только подставляет данные. Это аккуратнее и ближе к компонентному мышлению.
Ускоряем вставку через DocumentFragment
Если элементов много, лучше сначала собрать их во фрагмент, а затем один раз добавить в DOM. Это снижает количество операций с реальной страницей.
const fragment = document.createDocumentFragment();
products.forEach((product) => {
const card = template.content.cloneNode(true);
card.querySelector('.product-card__title').textContent = product.title;
card.querySelector('.product-card__price').textContent = `${product.price} ₽`;
const image = card.querySelector('.product-card__image');
image.src = product.image;
image.alt = product.title;
fragment.append(card);
});
list.append(fragment);
Для маленьких списков разница почти незаметна, но для сотен элементов такой приём полезен.
Обработчики событий: где их добавлять
После клонирования шаблона можно назначить обработчик кнопке внутри карточки:
products.forEach((product) => {
const card = template.content.cloneNode(true);
const button = card.querySelector('.product-card__button');
card.querySelector('.product-card__title').textContent = product.title;
button.addEventListener('click', () => {
console.log(`Добавлен товар: ${product.title}`);
});
list.append(card);
});
Если карточек очень много, лучше использовать делегирование событий на контейнере, но для простых случаев прямой обработчик вполне понятен.
Важные советы по использованию template
cloneNode(true). Если передать false, вложенная разметка не скопируется.textContent для текста. Это безопаснее, чем вставлять данные через innerHTML.alt у изображений. Это важно для доступности и SEO.product-card-template, а не просто tpl1.Когда использовать HTML template
Тег <template> хорошо подходит для:
Если вы только осваиваете современную вёрстку и хотите уверенно понимать, где заканчивается HTML и начинается логика JavaScript, посмотрите практический курс «Вёрстка сайта с нуля 2.0»: он поможет системно прокачать базу и собирать страницы более осознанно.
Типичные ошибки новичков
Ошибка 1: пытаться искать элементы шаблона напрямую на странице.
// Неправильно: элемент внутри template не находится как обычный видимый блок
const title = document.querySelector('.product-card__title');
Искать элементы нужно внутри клонированного фрагмента:
const card = template.content.cloneNode(true);
const title = card.querySelector('.product-card__title');
Ошибка 2: вставлять пользовательский HTML без проверки. Если данные пришли от пользователя, используйте textContent, а не innerHTML.
Ошибка 3: забывать, что template не отображается без JavaScript. Для критичного контента лучше иметь серверную разметку или fallback.
Итог
<template> в HTML5 — простой и полезный инструмент для повторяющейся разметки. Он помогает держать HTML отдельно от логики, безопасно подставлять данные и создавать элементы интерфейса без тяжёлых библиотек. Для новичков это отличный шаг от статичной страницы к динамическому интерфейсу, а для продолжающих разработчиков — удобный способ писать чище и поддерживаемее.