Follow AiTechWorlds on LinkedIn for professional AI content!Follow Now →
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, "&amp;")
        .replace(/</g, "&lt;")
        .replace(/>/g, "&gt;")
        .replace(/"/g, "&quot;");
    
    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: &lt;script&gt;alert('xss')&lt;/script&gt;</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 this course's notes on Telegram!

Free cheat sheets, summaries & practice exercises

Get Notes Free →
!