Problem Solved

JavaScript · template literals

Home › Courses › JavaScript › Problems › Template literals
🟨 Concept · 3 min read

Template literals.
Backticks, ${}, multi-line.

Template literals — the ones with backticks — are the modern way to build strings in JavaScript. They interpolate variables with ${'{}'}, they preserve line breaks, and they can be "tagged" with a function for advanced processing. If you're still concatenating strings with +, template literals are simpler and less error-prone. This page covers the syntax, the differences from quotes, and the tagged-template pattern that powers styled-components and GraphQL.

Short answer: Use backticks for any string with a variable or a newline. `Hello, ${'${name}'}` instead of 'Hello, ' + name. Multi-line strings just work — no \n escapes needed. Expression interpolation accepts any JS: ${'${a + b}'}, ${'${user.active ? "yes" : "no"}'}. Tagged templates (fn`...`) let a function process the template — rare in app code, common in libraries. Use backticks by default for anything non-trivial; use quotes for plain literal strings.

✅ The three differences from quotes

Why backticks are the default in modern JavaScript.

Interpolation

`Hi, ${'${name}'}` — embed any expression. Quotes need + concatenation.

Multi-line

Backticks preserve line breaks. Quotes need \n or concatenation.

Tagged templates

fn`...` — a function processes the template. Only backticks support this.

No escaping

Backticks don't need escaped quotes. You can use " and ' freely inside.

✅ Before and after

The same strings, quotes vs backticks.

interpolation.js
const name = 'Alice';
const age = 30;
const role = 'admin';

// ❌ Concatenation with quotes
const a = 'Hello, ' + name + '!';
const b = 'Name: ' + name + ', Age: ' + age;
const c = role === 'admin' ? 'Admin access' : 'Limited access';
const d = "Status: " + (age >= 18 ? 'adult' : 'minor');

// ✅ Template literals
const a2 = `Hello, ${name}!`;
const b2 = `Name: ${name}, Age: ${age}`;
const c2 = `${role === 'admin' ? 'Admin access' : 'Limited access'}`;
const d2 = `Status: ${age >= 18 ? 'adult' : 'minor'}`;

console.log(a);  console.log(a2);
console.log(b);  console.log(b2);
console.log(c);  console.log(c2);
console.log(d);  console.log(d2);

// Output is identical — only the syntax differs.
Output:
Hello, Alice!
Hello, Alice!
Name: Alice, Age: 30
Name: Alice, Age: 30
Admin access
Admin access
Status: adult
Status: adult

Why template literals are better:

1. No quote escaping
   ❌ "It's " + user + "'s turn"
   ✅ `It's ${user}'s turn`

2. No + operators between parts
   ❌ 'Hello, ' + name + ', you are ' + age
   ✅ `Hello, ${name}, you are ${age}`

3. Ternaries fit naturally
   ❌ 'Status: ' + (active ? 'on' : 'off')
   ✅ `Status: ${active ? 'on' : 'off'}`

4. Fewer bugs
   Concatenation with numbers is easy to get wrong:
   ❌ 'Total: ' + a + b   // 'Total: 12' (a=1, b=2, not 3)
   ✅ `Total: ${a + b}`   // 'Total: 3'

5. Expressions, not just variables
   ✅ `${a + b}`, `${user?.name}`, `${items.length}`
   Any expression works.

The one thing to watch:
  `${a}${b}` is string concatenation.
  `${a + b}` is arithmetic, then string.
  Different results. Be intentional.

✅ Multi-line strings

Backticks preserve newlines.

multiline.js
// ❌ Without backticks — escape newlines
const email1 =
  'Dear ' + name + ',\n\n' +
  'Thank you for your order.\n' +
  'Your total is $' + total + '.\n\n' +
  'Best regards,\n' +
  'The Team';

// ✅ With backticks — natural line breaks
const email2 = `Dear ${name},

Thank you for your order.
Your total is $${total}.

Best regards,
The Team`;

console.log(email2);
// Dear Alice,
//
// Thank you for your order.
// Your total is $99.
//
// Best regards,
// The Team
The output is the same.
The difference is the source code.

Without backticks:
  → Every line needs explicit \n
  → Every variable needs + concatenation
  → Every quote needs escaping
  → The code doesn't look like the output

With backticks:
  → Lines break naturally
  → Variables interpolate with ${}
  → No escaping needed
  → The code looks like the output

For anything more than one line, backticks win.

⚠️ Indentation matters:
   const msg = `Hello
   World`;
   → "Hello\nWorld"  (leading spaces preserved)
   → if you indent the second line for readability,
     those spaces are in the string

⚠️ To strip indentation, use a tagged template
   or process the string after:
   const clean = msg.replace(/^ +/gm, '');

⚠️ This is why template literals for HTML or SQL
   need care:
   const html = `
     

${content}

`; → leading whitespace is part of the string → for HTML, whitespace usually doesn't matter → for SQL or config files, it often does

✅ Tagged templates

A function that processes the template.

tagged.js
// Tagged template — the function receives
// the static parts and the dynamic values
function tag(strings, ...values) {
  console.log(strings);
  console.log(values);
  return strings.reduce((result, str, i) => {
    return result + str + (values[i] ?? '');
  }, '');
}

const name = 'Alice';
const age = 30;

tag`Hello, ${name}. You are ${age}.`;

// strings: ['Hello, ', '. You are ', '.']
// values:  ['Alice', 30]
// returns: 'Hello, Alice. You are 30.'

// The function can transform values
function upper(strings, ...values) {
  return strings.reduce((result, str, i) => {
    return result + str + String(values[i] ?? '').toUpperCase();
  }, '');
}

console.log(upper`Hi ${name}, you are ${age}`);
// "Hi ALICE, you are 30"
Tagged template anatomy:

  tag`Hello, ${name}.`

1. `tag` is a function.
2. The template is passed to it.
3. The function receives:
   strings: the static parts as an array
   values:  the interpolated expressions
4. The function returns whatever it wants
   — usually a string, but it could be
     an object, an array, a React element,
     a parsed AST.

Real-world uses:

✅ styled-components
   styled.div`color: red; padding: ${padding}`
   → returns a React component

✅ GraphQL (gql tag)
   gql`query { user { name } }`
   → returns a query AST

✅ lit-html
   html`

${content}

` → returns a TemplateResult ✅ SQL query builders (sql-template-strings) sql`SELECT * FROM users WHERE id = ${id}` → returns a parameterized query object Why use tagged templates: → The function gets the raw template parts AND the values separately, so it can escape, validate, or transform each. → This is how SQL injection is prevented: the values never get concatenated into the query string — they're passed as parameters. → It's how libraries like styled-components parse CSS safely. For app code, you almost never write a tag yourself. You use ones from libraries. But knowing what they are makes the library's behavior less magical.

Don't use ${'{a}'}${'{b}'} when you mean ${'{a + b}'}. This is the most common template-literal bug — and it's subtle. `${'${a}${b}'}` concatenates the string forms of a and b. If a = 1 and b = 2, the result is "12", not "3". For strings, the difference doesn't matter. For numbers, it does. When you want arithmetic, put both operands inside one ${'{}'}: ${'${a + b}'}. When you want concatenation, keep them separate. Be explicit about which you mean — the fix is one character, but the bug is silent.

⚠️ Common mistakes

The template-literal mistakes that cost real time.

1. Forgetting the backtick

'${name}' is literal text. Fix: `${name}`.

2. ${'${a}'}${'{b}'} when you meant ${'{a + b}'}

Concatenation instead of arithmetic. Fix: put the expression in one ${'{}'}.

3. Indentation inside multi-line templates

Leading spaces become part of the string. Fix: process with .replace() or a tag.

4. $ without {'{}'}

`Price: $${price}` — $ is literal, ${'${price}'} interpolates. Fix: escape $ if needed, or use ${'${"$"}'}.

5. Nested templates getting unreadable

Three levels deep. Fix: extract into variables.

6. Using template literals for plain strings

`hello` works but quotes are simpler. Fix: quotes for plain literals, backticks for interpolation.

7. Forgetting that ${'${}'} evaluates the expression

`${'${user.name}'}` — if user is undefined, throws. Fix: ${'${user?.name ?? ""}'}.

8. Not using tagged templates for HTML

Raw interpolation in HTML is an XSS risk. Fix: use a library like lit-html that escapes.

❓ Frequently asked

What are template literals in JavaScript?

Template literals are a string syntax that uses backticks instead of quotes. They support interpolation with ${expression}, multi-line strings without escape characters, and tagged templates. Example: const greeting = `Hello, ${name}!`. Added in ES2015, they're the modern default for any string with variables or newlines.

What is the difference between quotes and backticks?

Three differences. (1) Interpolation: backticks support ${expression}, quotes don't. (2) Multi-line: backticks preserve line breaks, quotes require \n or concatenation. (3) Tagged templates: only backticks can be tagged with a function. For simple strings, there's no difference. For anything with variables or newlines, backticks are cleaner.

How do I use ${} in a template literal?

Put an expression inside ${} inside backticks: `Hello, ${name}`. The expression can be any JavaScript — a variable, a function call, an arithmetic operation, a ternary. `Sum: ${a + b}`, `Status: ${user.active ? 'online' : 'offline'}`. The braces are required — ${} always, not $.

What are tagged templates?

A tagged template is a template literal prefixed with a function name: html`

${content}

`. The function receives the static parts of the template as an array and the interpolated values as additional arguments. It can process them however it wants. This is how styled-components, GraphQL's gql, and lit-html work.

Can I nest template literals?

Yes, but be careful with readability. `outer ${`inner ${value}`}` works — the inner template is evaluated first. This is useful for conditional rendering: `${user ? `Hello, ${user.name}` : 'Hello, guest'}`. But three levels of nesting is unreadable. Fix: extract the nested part into a variable.

Do template literals affect performance?

Not meaningfully. Template literals are parsed once and evaluate to a string, just like concatenation. In micro-benchmarks, template literals can be slightly faster. But the difference is in nanoseconds. Choose based on readability. `Hello, ${name}` is clearer than 'Hello, ' + name.

🔗 Continue learning

🗺️ JavaScript learning path
The full roadmap from variables to async — every concept in order

Next in this series:

📄 JSON.parse and JSON.stringify
The two methods — and the edge cases that bite
← All JavaScript problems
Problem solved · JavaScript