Interpolation in JS: A guide to template literals

Template literals (also called template strings) are the ES6 feature that changed how JavaScript developers write cleaner, data-driven text. Before 2015, embedding a variable inside a string meant concatenating fragments with + and carefully counting quotation marks.

Today, interpolation in JS takes a single backtick-delimited expression and inlines any variable or computation right where you need it. This guide covers everything from the basic ${} syntax through multiline strings, nested expressions and tagged templates, with runnable examples at every step.

What is string interpolation in JavaScript?

String interpolation means inserting variable values or computed expressions directly into a string literal, so the runtime fills them in when the line executes. In JavaScript the mechanism is template literals: a string wrapped in backticks (`) rather than single or double quotes. Anywhere you write ${expression} inside those backticks, JavaScript evaluates the expression and coerces the result to a string before embedding it. You can think of it as a slot in the string that gets filled at runtime, making static text flow without manual concatenation.

Template literals syntax

The three characters that define a template literal are the backtick, the dollar sign and the curly braces.

const name = 'Alice';
const greeting = `Hello, ${name}!`;
console.log(greeting); // Hello, Alice!

The backtick opens and closes the literal. Everything between the backticks is part of the string except for ${...} placeholders. Inside ${...} you write any valid JavaScript expression (a variable, a function call, arithmetic, a ternary) and the engine evaluates it.

Escaping backticks and dollar signs

To include a literal backtick inside a template literal, prefix it with a backslash:

const tick = `Back\`tick`;
console.log(tick); // Back`tick

To include a literal ${ without triggering interpolation, escape the dollar sign:

const raw = `Price: \${amount}`;
console.log(raw); // Price: ${amount}

Variable interpolation vs string concatenation

The old way to embed a variable used the + operator to concatenate string fragments:

const user = 'Bob';
const score = 42;
const msg = 'Player ' + user + ' scored ' + score + ' points.';

This works but the readability degrades fast when you have more than two variables. Template literals remove the noise:

const user = 'Bob';
const score = 42;
const msg = `Player ${user} scored ${score} points.`;

The string reads exactly as it will appear, with variables sitting in context. That makes review faster and bugs easier to spot. For any greenfield JavaScript code written against ES6 or later (which covers every modern browser and all maintained Node.js versions), template literals are the preferred approach. See our JavaScript string trim method guide for other string operations that pair well with this pattern.

Expressions inside template literals

The placeholder accepts any expression JavaScript can evaluate, including variables, function calls, arithmetic and ternaries.

Arithmetic and method calls

const price = 120;
const tax = 0.18;
console.log(`Total with tax: ${(price * (1 + tax)).toFixed(2)}`);
// Total with tax: 141.60

const fruit = 'mango';
console.log(`Uppercase: ${fruit.toUpperCase()}`);
// Uppercase: MANGO

Ternary expressions

Ternaries work cleanly inside ${} for inline conditionals:

const age = 20;
const status = `You are ${age >= 18 ? 'an adult' : 'a minor'}.`;
console.log(status); // You are an adult.

Keep expressions short. If the logic gets complex, extract it into a variable first, then reference the variable inside the template. That keeps the string readable and the logic testable.

Function calls

You can call a function and inline its return value:

function titleCase(str) {
  return str.replace(/\b\w/g, c => c.toUpperCase());
}

const title = `Welcome, ${titleCase('john doe')}!`;
console.log(title); // Welcome, John Doe!

Multiline strings

Before ES6, multiline strings required the \n escape character:

const old = 'Line one\nLine two\nLine three';

Template literals treat a literal newline in source code as part of the string, so you write exactly what you want:

const address = `
  123 Main Street
  Springfield, IL 62701
  United States
`;
console.log(address);

Output preserves the newlines and indentation exactly as written. This makes template literals ideal for multiline HTML snippets, SQL query strings and config blocks. One thing to keep in mind: the first newline after the opening backtick is included in the string. If you want to avoid a leading blank line, start the content on the same line as the backtick or trim the result.

// no leading newline
const sql = `SELECT id, name
FROM users
WHERE active = 1`;

For a thorough look at all the techniques available, check our article on creating multiline strings in JavaScript.

Nested template literal expressions

You can place a template literal inside the ${...} of another template literal. This sounds odd at first, but it is the cleanest way to handle conditional string fragments:

const location = 'Houston, Texas';
const venue = 'Toyota Center';

// Without nesting — verbose
const label1 = `${location}${venue ? ' (' + venue + ')' : ''}`;

// With nesting — cleaner
const label2 = `${location}${venue ? ` (${venue})` : ''}`;
console.log(label2); // Houston, Texas (Toyota Center)

Once inside ${...}, the parser opens a new expression context, so a fresh pair of backticks starts a nested template rather than closing the outer one. For anything beyond a simple ternary, readability improves by assigning the inner result to a variable:

const suffix = venue ? ` (${venue})` : '';
const label3 = `${location}${suffix}`;

A common pattern in practice is building a list of HTML items from an array using .map() nested inside a template literal:

const movies = ['Dunkirk', 'Arrival', 'Mad Max'];

const html = `
<ul>
  ${movies.map(m => `<li>${m}</li>`).join('\n  ')}
</ul>
`;
console.log(html);
/*
<ul>
  <li>Dunkirk</li>
  <li>Arrival</li>
  <li>Mad Max</li>
</ul>
*/

The outer template holds the <ul> wrapper. The .map() expression produces a new array of <li> strings using inner template literals. Then .join() stitches them using a newline and indentation. This pattern eliminates manual string concatenation inside loops entirely.

Tagged templates

Tagged templates are the advanced form of template literals. A tag is a function that receives the string parts and the interpolated values as separate arguments, letting you process or reshape the final string before it is returned.

How tags work

Prefix any template literal with a function reference:

function tag(strings, ...values) {
  console.log(strings); // array of raw string segments
  console.log(values);  // array of interpolated values
}

const name = 'Mike';
const age = 28;
tag`That ${name} is ${age} years old.`;
// strings: ['That ', ' is ', ' years old.']
// values: ['Mike', 28]

strings is a frozen array of the literal text segments between the placeholders. values (collected with rest parameters) is an array of the evaluated expressions. The tag function can combine them however it likes and return anything: a string, a DOM node, an object.

Building a practical sanitizer

Tagged templates are widely used in libraries that need to sanitize user-supplied values before inserting them into sensitive contexts. Here is a minimal HTML sanitizer tag:

function safeHtml(strings, ...values) {
  const escaped = values.map(v =>
    String(v)
      .replace(/&amp;/g, '&amp;amp;')
      .replace(/&lt;/g, '&amp;lt;')
      .replace(/>/g, '&amp;gt;')
      .replace(/"/g, '&amp;quot;')
  );
  return strings.reduce((acc, str, i) => acc + str + (escaped[i] ?? ''), '');
}

const userInput = '&lt;script>alert("xss")&lt;/script>';
const output = safeHtml`&lt;p>User said: ${userInput}&lt;/p>`;
console.log(output);
// &lt;p>User said: &amp;lt;script&amp;gt;alert(&amp;quot;xss&amp;quot;)&amp;lt;/script&amp;gt;&lt;/p>

Production query builders like sql-template-strings and CSS-in-JS libraries like styled-components use exactly this pattern.

The raw property and String.raw

The strings array passed to a tag also has a .raw property that holds the unprocessed escape sequences as they appear in source. The \n stays \n rather than being converted to a newline character:

function showRaw(strings) {
  console.log(strings[0]);     // processed: actual newline
  console.log(strings.raw[0]); // raw: the two characters \n
}
showRaw`line1\nline2`;

The built-in String.raw tag gives you the raw string directly:

const path = String.raw`C:\Users\name\Documents`;
console.log(path); // C:\Users\name\Documents  (backslashes preserved)

This is useful for Windows file paths, LaTeX strings and regular expression source text where backslashes should not be treated as escape characters.

Building HTML markup with template literals

Template literals are particularly good for constructing HTML markup that depends on data. Before ES6 this required nested string concatenation that was both fragile and hard to review:

// Old way
const card =
  '&lt;div class="card">' +
  '&lt;h2>' + user.name + '&lt;/h2>' +
  '&lt;p>Age: ' + user.age + '&lt;/p>' +
  '&lt;/div>';

With template literals the markup structure stays visible:

const user = { name: 'Dana', age: 31, role: 'engineer' };

const card = `
&lt;div class="card">
  &lt;h2>${user.name}&lt;/h2>
  &lt;p>Age: ${user.age}&lt;/p>
  &lt;p>Role: ${user.role}&lt;/p>
&lt;/div>
`.trim();

The same technique works well with the Temporal API when you need to format dates into strings. See our JavaScript Temporal API guide for examples of how Intl.DateTimeFormat and template literals compose together.

String interpolation before ES6

Template literals are the right tool in modern JavaScript, but knowing the older patterns matters when you maintain legacy code or need to run in environments without ES6 support.

String concatenation with +: the original approach. Works everywhere but becomes unreadable with multiple variables.

String.prototype.concat(): functionally the same as +, rarely used in practice:

const result = 'Hello, '.concat(name, '!');

Array.join(): useful when you are building a string from many parts in a loop:

const parts = ['Hello', name, 'you have', count, 'messages'];
const msg = parts.join(' ');

Custom interpolation function: some older codebases used a regex-based replacer to simulate ${} syntax before ES6 landed. You would pass a template string and a values object:

function interpolate(template, values) {
  return template.replace(/\${(\w+)}/g, (_, key) => values[key] ?? '');
}

const msg = interpolate('Hello, ${name}!', { name: 'Alice' });
console.log(msg); // Hello, Alice!

This covers the core patterns. For converting interpolated numeric strings into actual numbers, see our guide on converting strings to integers in Node.js.

Mistakes to avoid in production

Using the wrong quote character

Template literals only work with backticks. Single or double quotes treat ${} as plain text:

const wrong = "Hello, ${name}"; // outputs the literal characters $, {, n, a, m, e, }
const right = `Hello, ${name}`; // outputs the value of name

Forgetting to encode URL parameters

When building a URL with user-supplied values, always pass each variable through encodeURIComponent:

const query = 'hello world';

// broken — space character in URL
const bad = `https://example.com/search?q=${query}`;

// correct
const good = `https://example.com/search?q=${encodeURIComponent(query)}`;

Whitespace in multiline templates

Leading whitespace inside a template literal is part of the string. If you indent the content for readability, the indentation goes into the output. Use .trim() on the result, or use String.raw with a dedent helper if consistent indentation removal matters. For scope inside arrow functions used as tag processors, keep in mind that arrow functions capture this lexically, which matters when your tag function is a class method.

Mixing template literals and concatenation

Mixing the two styles in one expression is valid JavaScript but confusing to read. Pick one and stay consistent across a codebase:

// confusing mix
const bad = `Hello ` + name + `, you have ${count} messages`;

// consistent
const good = `Hello ${name}, you have ${count} messages`;

Key takeaways

  • Template literals use backticks and ${expression} to embed any JavaScript value or expression in a string.
  • They replace + concatenation with cleaner, more readable code.
  • Newlines inside backticks are literal. No \n escape needed for multiline strings.
  • Nesting template literals inside ${...} works because the parser opens a new expression context.
  • Tagged templates pass the string segments and values to a function, letting you sanitize, translate or reshape output.
  • String.raw is a built-in tag that returns the unprocessed escape sequences.
  • Template literals do not escape user data. Sanitize before embedding in URLs or HTML.

Frequently asked questions (FAQs)

What is interpolation in JavaScript?

Interpolation means embedding a variable or expression inside a string so the runtime replaces it with its value. Template literals with ${} are the standard JavaScript way to do this.

How do you use template literals in JavaScript?

Wrap your string in backticks and place any variable or expression inside ${}. For example: `Hello, ${name}!` outputs “Hello, Alice!” when name is “Alice”.

What is the difference between template literals and string concatenation?

Template literals embed values inline using ${} inside backticks. String concatenation joins fragments using +. Template literals are easier to read and less error-prone.

Can you put an if/else inside a template literal?

Use a ternary inside ${}: `Status: ${isActive ? 'online' : 'offline'}`. For full if/else logic, compute the value in a separate variable and reference it in the template.

What are tagged template literals used for?

Tagged templates pass the string parts and interpolated values to a function. They are used in libraries for HTML sanitization, SQL query building, CSS-in-JS styling and internationalization.

Do template literals work in all browsers?

Yes. Template literals have been supported in all major browsers since 2016: Chrome 51, Firefox 54, Edge 15 and Safari 10. They are not supported in Internet Explorer 11.

How do you escape a backtick inside a template literal?

Place a backslash before the backtick: `Back\`tick`. To keep a literal ${, escape the dollar sign: `\${literal}`.

Final conclusion

Template literals are one of the most used ES6 features in daily JavaScript work. Once you get used to them, going back to manual concatenation feels like a step backwards. Practice the tagged template pattern next. It opens the door to a class of string processing that is hard to achieve cleanly any other way.

Aditya Gupta
Aditya Gupta
Articles: 512