14 minLesson 11 of 35
Modern ES6+ JavaScript
Template Literals & Tagged Templates
Template Literals & Tagged Templates
Template literals replace old string concatenation with a powerful syntax that supports multi-line strings, embedded expressions, and even custom processing via tagged templates.
Basic Template Literals
// Old way — messy concatenation
const greeting = "Hello, " + user.name + "! You have " + count + " messages.";
// Template literal — use backticks and ${expression}
const greeting = `Hello, ${user.name}! You have ${count} messages.`;
// Any JavaScript expression works inside ${}
const result = `${a} + ${b} = ${a + b}`;
const status = `Status: ${isOnline ? "Online" : "Offline"}`;
const upper = `${name.toUpperCase()}`;
const computed = `Total: $${(price * quantity).toFixed(2)}`;
Multi-Line Strings
// Old way — escape sequences or concatenation
const html = "<div>\n <h1>Hello</h1>\n <p>World</p>\n</div>";
// Template literals preserve newlines naturally
const html = `
<div>
<h1>Hello</h1>
<p>World</p>
</div>
`;
// SQL queries
const query = `
SELECT id, name, email
FROM users
WHERE active = true
AND created_at > ${cutoffDate}
ORDER BY name ASC
LIMIT ${limit}
`;
// Email templates
const email = `
Dear ${customer.name},
Thank you for your order #${order.id}.
Your ${order.items.length} items will be delivered by ${order.deliveryDate}.
Total: $${order.total.toFixed(2)}
Best regards,
The Team
`;
Expressions Inside Templates
const cart = [
{ name: "Widget", price: 9.99, qty: 2 },
{ name: "Gadget", price: 24.99, qty: 1 }
];
const total = cart.reduce((sum, item) => sum + item.price * item.qty, 0);
const receipt = `
Order Summary
=============
${cart.map(item => ` ${item.name} × ${item.qty}: $${(item.price * item.qty).toFixed(2)}`).join("\n")}
=============
Total: $${total.toFixed(2)}
`;
// Nested template literals
const tableRows = users.map(u => `
<tr>
<td>${u.id}</td>
<td>${u.name}</td>
<td>${u.email}</td>
<td>${u.active ? "Active" : "Inactive"}</td>
</tr>
`).join("");
const table = `<table><tbody>${tableRows}</tbody></table>`;
Tagged Templates
Tagged templates pass the template to a function for custom processing. The tag is a function placed immediately before the backtick:
// Tag function signature:
// tag(strings, ...values)
// strings — array of literal string parts
// values — array of interpolated expression results
function highlight(strings, ...values) {
return strings.reduce((result, str, i) => {
const value = values[i - 1];
return result + `<mark>${value}</mark>` + str;
}, strings[0]);
}
const name = "Alice";
const score = 98;
const message = highlight`Player ${name} scored ${score} points!`;
// "Player <mark>Alice</mark> scored <mark>98</mark> points!"
Practical Tagged Templates
// SQL sanitization — prevent injection
function sql(strings, ...values) {
const sanitized = values.map(v =>
typeof v === "string" ? v.replace(/'/g, "''") : v
);
return strings.reduce((query, str, i) =>
query + (sanitized[i - 1] ?? "") + str
);
}
const userInput = "'; DROP TABLE users; --";
const query = sql`SELECT * FROM users WHERE name = '${userInput}'`;
// Safe — apostrophes are escaped
// HTML escaping
function safeHtml(strings, ...values) {
const escape = str => String(str)
.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/"/g, """);
return strings.reduce((html, str, i) =>
html + (i > 0 ? escape(values[i - 1]) : "") + str
);
}
const userContent = "<script>alert('xss')</script>";
const safe = safeHtml`<p>User said: ${userContent}</p>`;
// <p>User said: <script>alert('xss')</script></p>
// CSS-in-JS (Styled Components uses this pattern)
function css(strings, ...values) {
return strings.reduce((acc, str, i) =>
acc + (values[i - 1] ?? "") + str
);
}
const Button = styled.button`
background: ${props => props.primary ? "#0070f3" : "white"};
color: ${props => props.primary ? "white" : "#0070f3"};
padding: 0.5rem 1rem;
border-radius: 4px;
`;
String.raw
A built-in tagged template that returns the raw string without processing escape sequences:
// Normal template literals process escape sequences
console.log(`Line 1\nLine 2`);
// Line 1
// Line 2
// String.raw preserves the backslash literally
console.log(String.raw`Line 1\nLine 2`);
// Line 1\nLine 2
// Useful for Windows paths and regex patterns
const path = String.raw`C:\Users\Alice\Documents`;
const regex = new RegExp(String.raw`\d+\.\d+`);
Template Literals vs String Concatenation
// Performance note: for simple cases, both are fast
// Template literals win on readability for anything complex
// Long concatenation (unreadable)
const url = baseUrl + "/api/" + version + "/users/" + userId + "?include=" + fields.join(",");
// Template literal (clear)
const url = `${baseUrl}/api/${version}/users/${userId}?include=${fields.join(",")}`;
Next lesson: ES Modules — import and export for modular, maintainable code.
📱
Get Notes Free →Get this course's notes on Telegram!
Free cheat sheets, summaries & practice exercises