Template Literals
Template literals are strings delimited by backticks (`) instead of single or double quotes. Introduced in ES2015, they let you embed expressions directly inside a string, span multiple lines without escape sequences, and compose readable output without clumsy + concatenation. Once you start using them, plain string addition feels like a relic.
The basics: backticks
A template literal looks like an ordinary string, but it is wrapped in backticks. Inside, you can use single and double quotes freely without escaping them, which alone makes them handy for HTML and JSON-like text.
const plain = `Hello, world`;
const quotes = `She said "yes" and he said 'okay'`;
console.log(plain);
console.log(quotes);
Output:
Hello, world
She said "yes" and he said 'okay'
Interpolation with ${}
The headline feature is interpolation. Anything inside ${ ... } is evaluated as a JavaScript expression and its result is converted to a string and spliced into place. This replaces the noisy concatenation pattern that older code relied on.
const name = "Ada";
const age = 36;
// Old way
const oldWay = "Hello " + name + ", you are " + age + " years old.";
// Template literal
const newWay = `Hello ${name}, you are ${age} years old.`;
console.log(newWay);
Output:
Hello Ada, you are 36 years old.
The placeholder accepts any expression, not just variables — arithmetic, function calls, property access, and ternaries all work.
const price = 19.99;
const qty = 3;
const user = { isVip: true };
console.log(`Total: $${(price * qty).toFixed(2)}`);
console.log(`Welcome ${user.isVip ? "VIP" : "guest"}!`);
console.log(`In stock: ${["a", "b", "c"].length} items`);
Output:
Total: $59.97
Welcome VIP!
In stock: 3 items
Tip:
${}callsString()on its result. An object becomes[object Object]unless it definestoString(), and an array is joined with commas. Be explicit (JSON.stringify(obj)) when you want structured output.
Multiline strings
Inside backticks, newlines are preserved literally. There is no need for \n or string concatenation across lines, which makes templates ideal for emails, SQL, and markup.
const message = `Dear customer,
Your order has shipped.
Track it anytime in your account.
— The Team`;
console.log(message);
Output:
Dear customer,
Your order has shipped.
Track it anytime in your account.
— The Team
Beware that leading indentation counts as part of the string. If you indent a template to match your code, those spaces appear in the output. Trim or dedent when whitespace matters.
Embedded expressions and nesting
Because each ${} is a full expression, you can nest template literals inside one another. This is common when building markup from arrays with .map().
const items = ["Coffee", "Tea", "Juice"];
const html = `<ul>
${items.map((item) => ` <li>${item}</li>`).join("\n")}
</ul>`;
console.log(html);
Output:
<ul>
<li>Coffee</li>
<li>Tea</li>
<li>Juice</li>
</ul>
Nesting is powerful but readability drops fast. If a placeholder grows beyond a small expression, compute the value into a named variable first.
Readability vs concatenation
The table below contrasts the two approaches across common needs.
| Need | Concatenation (+) | Template literal |
|---|---|---|
| Insert a variable | "Hi " + name | `Hi ${name}` |
| Mix quotes | escape with \" | use quotes freely |
| Multiline text | "a\n" + "b" | literal newline |
| Run an expression | "x" + (a * b) | `x${a * b}` |
| Type coercion | manual String(x) | automatic |
Template literals win on clarity in almost every case. The main exception is appending a single short suffix, where + can read fine — but consistency usually favours backticks.
const product = "Headphones";
const stock = 12;
const summary = `${product} — ${stock > 0 ? `${stock} available` : "out of stock"}`;
console.log(summary);
Output:
Headphones — 12 available
Best practices
- Reach for template literals by default whenever a string contains a variable or expression.
- Keep
${}placeholders small; lift complex logic into a namedconstbefore interpolating. - Use
JSON.stringify()for objects and arrays instead of relying on default coercion. - Remember that indentation inside multiline templates becomes literal whitespace — dedent intentionally.
- Prefer
.map(...).join("\n")over manual concatenation when generating repeated lines. - For HTML built from user input, escape values to avoid injection — template literals do not sanitize.