JavaScript Template Literals
JavaScript template literals are useful because they make string-building honest. You can see the fixed text and the changing values in one place. The trap is thinking they are a templating engine. They are not. They interpolate expressions into strings, and they do not automatically escape HTML, SQL, URLs, or anything else for you.
Use them for readable string construction. Keep your security promises somewhere stronger than a pair of backticks.
The problem with concatenation
String concatenation works, but it gets noisy as soon as values and punctuation mix:
const name = "Ada";
const lessonCount = 12;
const message =
"Welcome back, " + name + ". You have " + lessonCount + " lessons left.";
The reader has to mentally stitch together quotes, plus signs, spaces, and variables. That is a lot of ceremony for one sentence.
Template literals use backticks and ${} placeholders:
const message = `Welcome back, ${name}. You have ${lessonCount} lessons left.`;
The sentence now reads like a sentence.
Interpolation accepts expressions
The code inside ${} can be any JavaScript expression.
const price = 9.99;
const quantity = 3;
const total = `Total: $${(price * quantity).toFixed(2)}`;
console.log(total); // "Total: $29.97"
That includes function calls:
const username = " Grace Hopper ";
const label = `User: ${username.trim().toUpperCase()}`;
console.log(label); // "User: GRACE HOPPER"
And ternaries:
const unread = 1;
const summary = `You have ${unread} unread message${unread === 1 ? "" : "s"}.`;
For the expression side of that example, see The Ternary Operator.
Multiline strings keep line breaks
Template literals preserve line breaks and whitespace:
const email = `Hello Ada,
Your account is ready.
Thanks,
JS Exercises`;
That is cleaner than writing \n repeatedly:
const email = "Hello Ada,\n\nYour account is ready.\n\nThanks,\nJS Exercises";
Be careful with indentation. The spaces in your source code become part of the string.
const html = `
<section>
<h2>${title}</h2>
</section>
`;
That leading newline and indentation are real characters. Usually that is fine for generated HTML. It can matter for text output, tests, and exact string comparisons.
Template literals do not escape unsafe content
This is the important failure mode:
const comment = "<img src=x onerror=alert(1)>";
const html = `<p>${comment}</p>`;
The template literal did exactly what you asked. It placed the string inside another string. It did not sanitize the value. If that string is later assigned to innerHTML, the browser parses it as HTML.
Prefer DOM APIs when rendering user-controlled text:
const paragraph = document.createElement("p");
paragraph.textContent = comment;
textContent treats the value as text. A template literal cannot make that guarantee by itself.
Tagged templates
A tagged template is a function call with special syntax. The tag receives the static string parts and the interpolated values separately.
function debug(strings, ...values) {
console.log(strings);
console.log(values);
}
const name = "Ada";
const count = 3;
debug`Hello ${name}, you have ${count} tasks.`;
The tag receives:
["Hello ", ", you have ", " tasks."]
["Ada", 3]
Libraries use this pattern for CSS-in-JS, GraphQL queries, SQL builders, and localization. The useful part is that the tag can process values separately from the raw string text.
Here is a tiny example that wraps interpolated values:
function mark(strings, ...values) {
return strings.reduce((result, part, index) => {
const value = values[index] === undefined ? "" : `<mark>${values[index]}</mark>`;
return result + part + value;
}, "");
}
const language = "JavaScript";
const result = mark`Learn ${language} today`;
console.log(result);
// "Learn <mark>JavaScript</mark> today"
That example is intentionally small. Real tagged-template libraries handle escaping and edge cases carefully. Do not copy a three-line blog demo into a payment app and call it architecture.
Common mistakes
Using quotes instead of backticks leaves the placeholder as plain text:
const name = "Ada";
console.log("Hello, ${name}!");
// "Hello, ${name}!"
console.log(`Hello, ${name}!`);
// "Hello, Ada!"
Forgetting that expressions run immediately can also surprise people:
const value = `Random: ${Math.random()}`;
console.log(value);
console.log(value);
Both logs show the same string because Math.random() ran when the template literal was created, not each time the string was read.
Escaping a backtick inside a template literal requires a backslash:
const markdown = `Use \`code\` for inline snippets.`;
Key Takeaways
- Template literals use backticks and interpolate expressions with
${}. - They preserve line breaks and whitespace exactly as written.
- They make string construction easier to read, especially with multiple values.
- They do not sanitize or escape unsafe content.
- Tagged templates let a function process string parts and interpolated values separately.