Skip to main content

Command Palette

Search for a command to run...

Template Literals in JavaScript

Updated
5 min read

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 \n characters.

  • Poor templating ergonomics: building HTML or multi-line text often needs arrays + join() or multiple concat() 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 =>
    ({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[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 encodeURIComponent inline:

    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.