Template Literals in JavaScript
Template literals (backtick strings) arrived in ES2015 and make string construction clearer, safer, and more expressive than manual concatenation. This article explains the problems with traditional concatenation, demonstrates template literal syntax and features (including tagged templates), and shows practical use cases and tips you can apply today.
Why traditional string concatenation is problematic
Readability: long chains of
+and interleaved quotes quickly become hard to scan.Error-prone: missing spaces, quotes, or
+signs introduce subtle bugs.Hard to compose: inserting expressions or multi-line content requires awkward escaping and manual
\ncharacters.Poor templating ergonomics: building HTML or multi-line text often needs arrays +
join()or multipleconcat()calls.Harder to maintain: refactoring or reordering pieces is more tedious.
Example — messy concatenation
const name = 'Ava';
const count = 3;
const s = 'Hello, ' + name + '! You have ' + count + ' unread messages.';
Problems: many + operators, manual spacing, and the final string shape is not visible at a glance.
Template literal syntax — the basics
Wrap strings with backticks:
`...`Embed expressions with
${...}Support true multi-line strings (preserve newlines)
Support tagged templates (a function receives string parts and substitution values)
Examples
const name = 'Ava';
const count = 3;
const msg = `Hello, \({name}! You have \){count} unread messages.`;
const price = 9.99;
const total = `Total: $${(price * 1.08).toFixed(2)}`;
const poem = `Roses are red,
Violets are blue,
Template literals
Make strings easy to do.`;
Embedding variables and expressions
Template literals accept any JavaScript expression inside ${...}:
Simple variables:
${var}Arithmetic and expressions:
${a + b}Array operations:
${arr.map(x => x*2).join(', ')}Function calls:
${formatDate(date)}Ternary / logical usage:
${isAdmin ? 'Admin' : 'User'}
Example with mixed expressions:
const items = [2, 4, 6];
const summary = `Count: \({items.length}, Sum: \){items.reduce((a,b)=>a+b,0)}, Doubled: ${items.map(n=>n*2).join(', ')}`;
Multi-line strings
Template literals preserve newlines and spacing as written. Beware of leading/trailing indentation when embedding template literals inside indented code.
Example:
const html = `
<article>
<h1>${title}</h1>
<p>${body}</p>
</article>
`.trim();
Tip: Use helper utilities (e.g., stripIndent from common libraries or a lightweight helper) to normalize indentation when needed.
Tagged templates (brief)
A tag is a function executed with the string parts and substitution values. Tags are powerful for safe templating, localization, DSLs, and custom parsing.
Simple safe HTML example:
function escapeHtml(str) {
return String(str).replace(/[&<>"']/g, s =>
({'&':'&','<':'<','>':'>','"':'"',"'":'''}[s]));
}
function html(strings, ...values) {
return strings.reduce((acc, s, i) => acc + s + (i < values.length ? escapeHtml(values[i]) : ''), '');
}
const userInput = '<script>alert(1)</script>';
const message = html`<p>${userInput}</p>`; // safe-escaped output
Tagged templates receive strings (array of literal parts) and values (substitutions) and return a string (or any other structure).
Use cases in modern JavaScript
Building URLs with
encodeURIComponentinline:const url = `https://example.com/search?q=\({encodeURIComponent(query)}&page=\){page}`;Constructing HTML or email templates (with proper escaping/tagging).
Logging and debugging messages (showing computed values inline).
DSLs and small templating systems using tagged templates.
Generating multi-line SQL, GraphQL, or config blocks (take care to parameterize queries to avoid injection).
Compare old concatenation vs template literals
Before:
const name = 'Sam';
const url = 'https://example.com/profile?user=' + encodeURIComponent(name) + '&ref=' + refId;
After:
const url = `https://example.com/profile?user=\({encodeURIComponent(name)}&ref=\){refId}`;
Benefits:
Fewer tokens and punctuation.
Final string shape is more visible.
Easier to edit and maintain.
Emphasize readability improvements
Visual continuity: the source shows the final string shape (especially for multi-line content).
Reduced visual noise: fewer
+signs and quote toggles make intent clearer.Safer composition: expression embedding makes it harder to forget spaces or concatenation points.
Easier refactoring: reordering parts or inserting new expressions is straightforward.
Practical tips and pitfalls
Avoid embedding complex logic directly in template expressions; prefer helper functions for clarity.
When building HTML, always escape untrusted data or use a safe tagged template.
Be aware of incidental whitespace in multi-line templates — use
.trim()or a dedent helper.Tagged templates can return non-strings (e.g., ASTs or JSX-like structures) — design accordingly.
Performance: template literals are generally as fast as concatenation for typical use, but don't micro-optimize readability for tiny gains.
Quick checklist for authors
Prefer template literals for readability and maintainability.
Escape or use a safe tag when inserting untrusted data into HTML.
Use helper functions to keep template expressions simple and readable.
Normalize indentation for multi-line templates when necessary.
Conclusion
Template literals are a small, expressive feature with outsized benefits: clearer code, safer templating when combined with tags, and far better ergonomics for multi-line and expression-rich strings. Convert concatenations where readability matters, and use tagged templates where safety or custom parsing is required.