Scripting
HTML5
The <template> element holds HTML content that is not rendered when the page loads. It serves as a blueprint for content that can be cloned and inserted into the document via JavaScript. Template content is inert—scripts don’t run, images don’t load, and styles don’t apply until the template is activated.
Interactive code playground requires JavaScript. Here's the code:
<template id="card-template">
<div class="card">
<h3 class="card-title"></h3>
<p class="card-description"></p>
<button class="card-btn">Learn More</button>
</div>
</template>
<div id="cards"></div>
<script>
const template = document.getElementById('card-template');
const container = document.getElementById('cards');
const data = [
{ title: 'Article 1', desc: 'First article description' },
{ title: 'Article 2', desc: 'Second article description' }
];
data.forEach(item => {
// Clone template content
const clone = template.content.cloneNode(true);
// Fill in the data
clone.querySelector('.card-title').textContent = item.title;
clone.querySelector('.card-description').textContent = item.desc;
// Append to document
container.appendChild(clone);
});
</script>
<style>
.card {
padding: 1em;
margin: 0.5em 0;
border: 1px solid #e5e7eb;
border-radius: 8px;
background: #f9fafb;
}
.card-title {
margin: 0 0 0.5em 0;
color: #1f2937;
}
.card-description {
color: #6b7280;
margin: 0 0 1em 0;
}
.card-btn {
padding: 0.5em 1em;
background: #3b82f6;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
</style>
< template id = " my-template " >
<!-- Content here is inert -->
Content inside <template> is completely inactive:
Interactive code playground requires JavaScript. Here's the code:
<template id="inert-demo">
<!-- This script doesn't run -->
<script>
alert('This will NOT execute!');
console.log('Template script - NOT executed');
</script>
<!-- This image doesn't load -->
<img src="https://example.com/image.jpg" alt="Not loaded">
<!-- This style doesn't apply -->
<style>
body { background: red; /* Doesn't apply */ }
</style>
<p>This content is hidden until activated.</p>
</template>
<div style="padding: 1em; background: #f3f4f6; border-radius: 4px;">
<strong>Template content is inert:</strong>
<ul>
<li>Scripts don't execute</li>
<li>Images don't load</li>
<li>Styles don't apply</li>
<li>Content not rendered</li>
<li>Not in DOM tree (separate)</li>
</ul>
</div>
<button onclick="activateTemplate()">Activate Template</button>
<div id="activated"></div>
<script>
function activateTemplate() {
const template = document.getElementById('inert-demo');
const clone = template.content.cloneNode(true);
document.getElementById('activated').appendChild(clone);
// Now scripts run, images load, etc.
}
</script>
<style>
button {
padding: 0.75em 1.5em;
background: #3b82f6;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
margin-top: 1em;
}
</style>
Interactive code playground requires JavaScript. Here's the code:
<template id="user-template">
<li class="user-item">
<img class="user-avatar" src="" alt="">
<div class="user-info">
<h4 class="user-name"></h4>
<p class="user-email"></p>
</div>
</li>
</template>
<ul id="user-list"></ul>
<button onclick="loadUsers()">Load Users</button>
<script>
function loadUsers() {
const users = [
{ name: 'Alice Johnson', email: 'alice@example.com',
avatar: 'data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" width="40" height="40"%3E%3Ccircle cx="20" cy="20" r="20" fill="%233b82f6"/%3E%3Ctext x="50%25" y="50%25" text-anchor="middle" dy=".3em" fill="white" font-size="20"%3EA%3C/text%3E%3C/svg%3E' },
{ name: 'Bob Smith', email: 'bob@example.com',
avatar: 'data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" width="40" height="40"%3E%3Ccircle cx="20" cy="20" r="20" fill="%2310b981"/%3E%3Ctext x="50%25" y="50%25" text-anchor="middle" dy=".3em" fill="white" font-size="20"%3EB%3C/text%3E%3C/svg%3E' },
{ name: 'Carol Davis', email: 'carol@example.com',
avatar: 'data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" width="40" height="40"%3E%3Ccircle cx="20" cy="20" r="20" fill="%23f59e0b"/%3E%3Ctext x="50%25" y="50%25" text-anchor="middle" dy=".3em" fill="white" font-size="20"%3EC%3C/text%3E%3C/svg%3E' }
];
const template = document.getElementById('user-template');
const list = document.getElementById('user-list');
users.forEach(user => {
const clone = template.content.cloneNode(true);
clone.querySelector('.user-avatar').src = user.avatar;
clone.querySelector('.user-name').textContent = user.name;
clone.querySelector('.user-email').textContent = user.email;
list.appendChild(clone);
});
}
</script>
<style>
#user-list {
list-style: none;
padding: 0;
margin: 1em 0;
}
.user-item {
display: flex;
align-items: center;
padding: 1em;
margin: 0.5em 0;
background: #f9fafb;
border-radius: 8px;
border: 1px solid #e5e7eb;
}
.user-avatar {
width: 40px;
height: 40px;
border-radius: 50%;
margin-right: 1em;
}
.user-info {
flex: 1;
}
.user-name {
margin: 0;
font-size: 1em;
color: #1f2937;
}
.user-email {
margin: 0.25em 0 0 0;
font-size: 0.9em;
color: #6b7280;
}
button {
padding: 0.75em 1.5em;
background: #3b82f6;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
</style>
Interactive code playground requires JavaScript. Here's the code:
<template id="row-template">
<tr>
<td class="product-name"></td>
<td class="product-price"></td>
<td class="product-stock"></td>
<td>
<button class="btn-edit">Edit</button>
<button class="btn-delete">Delete</button>
</td>
</tr>
</template>
<table>
<thead>
<tr>
<th>Product</th>
<th>Price</th>
<th>Stock</th>
<th>Actions</th>
</tr>
</thead>
<tbody id="products"></tbody>
</table>
<button onclick="loadProducts()">Load Products</button>
<script>
function loadProducts() {
const products = [
{ name: 'Laptop', price: '$999', stock: 15 },
{ name: 'Mouse', price: '$29', stock: 50 },
{ name: 'Keyboard', price: '$79', stock: 30 }
];
const template = document.getElementById('row-template');
const tbody = document.getElementById('products');
products.forEach(product => {
const clone = template.content.cloneNode(true);
clone.querySelector('.product-name').textContent = product.name;
clone.querySelector('.product-price').textContent = product.price;
clone.querySelector('.product-stock').textContent = product.stock;
clone.querySelector('.btn-edit').addEventListener('click', () => {
alert('Edit ' + product.name);
});
clone.querySelector('.btn-delete').addEventListener('click', function() {
this.closest('tr').remove();
});
tbody.appendChild(clone);
});
}
</script>
<style>
table {
width: 100%;
border-collapse: collapse;
margin: 1em 0;
}
th, td {
padding: 0.75em;
text-align: left;
border-bottom: 1px solid #e5e7eb;
}
th {
background: #f9fafb;
font-weight: 600;
color: #374151;
}
button {
padding: 0.5em 1em;
margin: 0 0.25em;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 0.9em;
}
.btn-edit {
background: #3b82f6;
color: white;
}
.btn-delete {
background: #ef4444;
color: white;
}
button:first-of-type {
background: #10b981;
color: white;
padding: 0.75em 1.5em;
margin-bottom: 1em;
}
</style>
Interactive code playground requires JavaScript. Here's the code:
<template id="modal-template">
<div class="modal-overlay">
<div class="modal">
<div class="modal-header">
<h3 class="modal-title"></h3>
<button class="modal-close">×</button>
</div>
<div class="modal-body"></div>
<div class="modal-footer">
<button class="btn-cancel">Cancel</button>
<button class="btn-confirm">Confirm</button>
</div>
</div>
</div>
</template>
<button onclick="showModal('Delete Item', 'Are you sure?')">
Show Modal
</button>
<div id="modal-container"></div>
<script>
function showModal(title, message) {
const template = document.getElementById('modal-template');
const container = document.getElementById('modal-container');
const clone = template.content.cloneNode(true);
clone.querySelector('.modal-title').textContent = title;
clone.querySelector('.modal-body').textContent = message;
clone.querySelector('.modal-close').addEventListener('click', closeModal);
clone.querySelector('.btn-cancel').addEventListener('click', closeModal);
clone.querySelector('.btn-confirm').addEventListener('click', () => {
alert('Confirmed!');
closeModal();
});
container.appendChild(clone);
}
function closeModal() {
document.getElementById('modal-container').innerHTML = '';
}
</script>
<style>
.modal-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
}
.modal {
background: white;
border-radius: 8px;
min-width: 400px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}
.modal-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 1em 1.5em;
border-bottom: 1px solid #e5e7eb;
}
.modal-title {
margin: 0;
font-size: 1.2em;
}
.modal-close {
background: none;
border: none;
font-size: 2em;
cursor: pointer;
color: #6b7280;
padding: 0;
width: 30px;
height: 30px;
line-height: 1;
}
.modal-body {
padding: 1.5em;
}
.modal-footer {
padding: 1em 1.5em;
border-top: 1px solid #e5e7eb;
display: flex;
justify-content: flex-end;
gap: 0.5em;
}
.btn-cancel {
padding: 0.75em 1.5em;
background: #e5e7eb;
border: none;
border-radius: 4px;
cursor: pointer;
}
.btn-confirm {
padding: 0.75em 1.5em;
background: #3b82f6;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
button:first-of-type {
margin-bottom: 1em;
}
</style>
Templates provide a DocumentFragment when cloned:
Interactive code playground requires JavaScript. Here's the code:
<template id="fragment-demo">
<p>Paragraph 1</p>
<p>Paragraph 2</p>
<p>Paragraph 3</p>
</template>
<div id="output"></div>
<button onclick="cloneTemplate()">Clone Template</button>
<script>
function cloneTemplate() {
const template = document.getElementById('fragment-demo');
// Get the content (DocumentFragment)
const content = template.content;
// Clone it (deep clone)
const clone = content.cloneNode(true);
console.log('Clone type:', clone.constructor.name);
// DocumentFragment
console.log('Children:', clone.children.length); // 3
// Append to document
document.getElementById('output').appendChild(clone);
}
</script>
<style>
button {
padding: 0.75em 1.5em;
background: #3b82f6;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
margin-bottom: 1em;
}
#output p {
padding: 0.5em;
background: #f3f4f6;
border-left: 3px solid #3b82f6;
margin: 0.5em 0;
}
</style> Interactive code playground requires JavaScript. Here's the code:
<template id="modify-demo">
<div class="message">
<span class="icon"></span>
<span class="text"></span>
</div>
</template>
<div id="messages"></div>
<button onclick="addMessage('success', '✓', 'Operation successful!')">
Success
</button>
<button onclick="addMessage('error', '✗', 'Operation failed!')">
Error
</button>
<script>
function addMessage(type, icon, text) {
const template = document.getElementById('modify-demo');
const clone = template.content.cloneNode(true);
// Modify before inserting
const messageDiv = clone.querySelector('.message');
messageDiv.classList.add('message-' + type);
clone.querySelector('.icon').textContent = icon;
clone.querySelector('.text').textContent = text;
document.getElementById('messages').appendChild(clone);
}
</script>
<style>
button {
padding: 0.75em 1em;
border: none;
border-radius: 4px;
cursor: pointer;
margin: 0.25em;
color: white;
}
button:first-of-type {
background: #10b981;
}
button:last-of-type {
background: #ef4444;
}
.message {
padding: 1em;
margin: 0.5em 0;
border-radius: 4px;
display: flex;
align-items: center;
gap: 0.75em;
}
.message-success {
background: #d1fae5;
color: #065f46;
}
.message-error {
background: #fee2e2;
color: #991b1b;
}
.icon {
font-weight: bold;
font-size: 1.2em;
}
</style>
Templates are fundamental to Web Components:
Interactive code playground requires JavaScript. Here's the code:
<template id="user-card">
<style>
.card {
padding: 1.5em;
border: 2px solid #e5e7eb;
border-radius: 8px;
background: white;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.name {
font-size: 1.2em;
font-weight: bold;
margin: 0 0 0.5em 0;
color: #1f2937;
}
.email {
color: #6b7280;
margin: 0;
}
</style>
<div class="card">
<h3 class="name"></h3>
<p class="email"></p>
</div>
</template>
<script>
class UserCard extends HTMLElement {
constructor() {
super();
// Attach shadow DOM
const shadow = this.attachShadow({ mode: 'open' });
// Clone template content
const template = document.getElementById('user-card');
const content = template.content.cloneNode(true);
// Fill in data from attributes
content.querySelector('.name').textContent =
this.getAttribute('name');
content.querySelector('.email').textContent =
this.getAttribute('email');
// Append to shadow DOM
shadow.appendChild(content);
}
}
customElements.define('user-card', UserCard);
</script>
<!-- Use the custom element -->
<user-card name="Jane Doe" email="jane@example.com"></user-card>
<user-card name="John Smith" email="john@example.com"></user-card>
Templates offer significant performance advantages:
Interactive code playground requires JavaScript. Here's the code:
<button onclick="testPerformance()">Test Performance</button>
<div id="perf-results" style="margin-top: 1em; padding: 1em;
background: #f3f4f6; border-radius: 4px;">
Click button to test
</div>
<template id="perf-template">
<div class="item">
<h4 class="title"></h4>
<p class="desc"></p>
</div>
</template>
<script>
function testPerformance() {
const iterations = 1000;
const results = document.getElementById('perf-results');
// Test innerHTML
const start1 = performance.now();
const container1 = document.createElement('div');
for (let i = 0; i < iterations; i++) {
container1.innerHTML +=
'<div class="item"><h4>' + i + '</h4><p>Description</p></div>';
}
const time1 = performance.now() - start1;
// Test template
const start2 = performance.now();
const container2 = document.createElement('div');
const template = document.getElementById('perf-template');
for (let i = 0; i < iterations; i++) {
const clone = template.content.cloneNode(true);
clone.querySelector('.title').textContent = i;
clone.querySelector('.desc').textContent = 'Description';
container2.appendChild(clone);
}
const time2 = performance.now() - start2;
results.innerHTML =
'<strong>Performance Results (' + iterations + ' items):</strong><br>' +
'innerHTML: ' + time1.toFixed(2) + 'ms<br>' +
'Template: ' + time2.toFixed(2) + 'ms<br>' +
'<strong>Template is ' + (time1 / time2).toFixed(1) + 'x faster!</strong>';
}
</script>
<style>
button {
padding: 0.75em 1.5em;
background: #3b82f6;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
</style> ⚠️ Slow, especially when repeated
1. Clone pre-parsed structure
✓ Fast, optimized by browser
Interactive code playground requires JavaScript. Here's the code:
<template id="comment-template">
<div class="comment">
<strong class="author"></strong>
<p class="text"></p>
<div class="replies"></div>
</div>
</template>
<div id="comments"></div>
<button onclick="loadComments()">Load Comments</button>
<script>
function loadComments() {
const data = [
{
author: 'Alice',
text: 'Great article!',
replies: [
{ author: 'Bob', text: 'I agree!' }
]
},
{
author: 'Carol',
text: 'Very helpful.',
replies: []
}
];
const template = document.getElementById('comment-template');
const container = document.getElementById('comments');
function createComment(comment) {
const clone = template.content.cloneNode(true);
clone.querySelector('.author').textContent = comment.author;
clone.querySelector('.text').textContent = comment.text;
// Add replies
const repliesDiv = clone.querySelector('.replies');
comment.replies.forEach(reply => {
const replyClone = createComment(reply);
repliesDiv.appendChild(replyClone);
});
return clone;
}
data.forEach(comment => {
container.appendChild(createComment(comment));
});
}
</script>
<style>
.comment {
padding: 1em;
margin: 0.5em 0;
border-left: 3px solid #3b82f6;
background: #f9fafb;
}
.author {
color: #1f2937;
}
.text {
margin: 0.5em 0;
color: #374151;
}
.replies {
margin-left: 1.5em;
}
.replies .comment {
border-left-color: #8b5cf6;
background: #faf5ff;
}
button {
padding: 0.75em 1.5em;
background: #3b82f6;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
margin-bottom: 1em;
}
</style>
Excellent Modern Support
The <template> element is widely supported:
Chrome : 26+ (2013)
Firefox : 22+ (2013)
Safari : 8+ (2014)
Edge : All versions
Opera : 15+ (2013)
Mobile : Widely supported
Polyfill : For older browsers, use template element polyfill .
<slot> - Web Components content insertion
<script> - JavaScript execution
Custom Elements - Web Components API
Shadow DOM - Encapsulated DOM trees
Use for repeated content : Perfect for lists, cards, etc.
Clone, don’t reuse : Always clone template content
Deep clone : Use cloneNode(true)
Modify before insert : Change clones before adding to DOM
Performance : Templates are faster than innerHTML for repeated use
Web Components : Ideal for custom element definitions
Keep simple : Templates are for structure, not logic
Accessibility : Ensure cloned content is accessible
Event listeners : Add after cloning, not in template
Naming : Use descriptive template IDs
Learn More: