Template Literals in JavaScript
Learn how JavaScript template literals fix string concatenation problems with interpolation, multi-line support, and tagged templates.
Template literals, introduced in ES6, replace messy string concatenation with a cleaner, more readable syntax. This post covers the problems they solve, how they work, and where they shine in modern JavaScript.

Imagine writing a letter by hand where every time you need to include someone's name, you have to stop writing, tape in a sticky note, and then resume writing. That's essentially what old-school JavaScript string concatenation felt like. Template literals are the upgrade: you just write the name right there, inline, without breaking your flow.
The Problem with Traditional String Concatenation
Before template literals, building dynamic strings in JavaScript meant gluing pieces together with the + operator. For simple cases it was fine. For anything real, it became a maintenance nightmare.
// User profile message
const name = "Atharv";
const role = "developer";
const years = 3;
const message =
"Hello, " +
name +
"! You are a " +
role +
" with " +
years +
" years of experience.";Count the quotes. Count the + signs. Count the spaces you have to manually insert before and after variables. Miss one and your output reads "Hello,Atharv!" with no space. Now imagine a URL with query params, or an HTML string built dynamically. It gets ugly fast.
Old Way:
"Hello, " + name + "! You are a " + role + " with " + years + " years."
↑ ↑ ↑ ↑ ↑ ↑
open close open close open close
quote + quote + quote + quote + quote + variable
Every variable needs quotes around the surrounding text.
Every space must be manually placed. Every typo is silent.Multi-line strings were even worse:
// Old multi-line: use \n and pray
const html =
"<div>\n" +
" <h1>" +
title +
"</h1>\n" +
" <p>" +
body +
"</p>\n" +
"</div>";Template Literal Syntax
Template literals use backticks instead of single or double quotes. That single change unlocks everything.
const greeting = `Hello, world!`;Looks similar so far. Here's where it gets useful.
Embedding Variables: String Interpolation
Inside a template literal, ${} is your escape hatch into JavaScript. Anything inside those curly braces gets evaluated and embedded directly into the string.
const name = "Atharv";
const role = "developer";
const years = 3;
const message = `Hello, ${name}! You are a ${role} with ${years} years of experience.`;No quotes to open and close around every piece. No + operators. The string reads like a sentence.
Template Literal Interpolation:
`Hello, ${name}! You are a ${role} with ${years} years.`
┌──┴──┐ ┌──┴──┐ ┌───┴───┐
│name │ │role │ │ years │
│"Atharv" │"developer" │ 3 │
└─────┘ └─────┘ └───────┘
↓
"Hello, Atharv! You are a developer with 3 years."The ${} can hold any valid JavaScript expression, not just variable names:
const a = 10;
const b = 5;
console.log(`Sum: ${a + b}`); // Sum: 15
console.log(`Max: ${Math.max(a, b)}`); // Max: 10
console.log(`Even? ${a % 2 === 0}`); // Even? trueYou can call functions, run ternary operators, access object properties: anything that evaluates to a value.
const user = { name: "Atharv", isPro: true };
const label = `${user.name} (${user.isPro ? "Pro" : "Free"})`;
// "Atharv (Pro)"Multi-line Strings
This is where template literals make old code look embarrassing. Newlines are preserved exactly as written. No \n, no string concatenation across lines.
Old Way vs Template Literal:
┌─────────────────────────────────────────────┐
│ Old Way │
│ │
│ "<div>\n" + │
│ " <p>" + text + "</p>\n" + │
│ "</div>" │
└─────────────────────────────────────────────┘
┌─────────────────────────────────────────────┐
│ Template Literal │
│ │
│ `<div> │
│ <p>${text}</p> │
│ </div>` │
│ │
│ What you write is what you get. │
└─────────────────────────────────────────────┘const title = "Modules";
const body = "Split your code into focused files.";
const card = `
<div class="card">
<h2>${title}</h2>
<p>${body}</p>
</div>
`;The indentation, the newlines, all of it is preserved in the output. This is massive for building HTML strings, SQL queries, or any multi-line text.
Use Cases in Modern JavaScript
URL building: Query strings used to be miserable to write.
const base = "https://api.example.com";
const userId = 42;
const page = 2;
const url = `${base}/users/${userId}/posts?page=${page}`;
// "https://api.example.com/users/42/posts?page=2"Logging with context: Print meaningful debug messages without the concatenation noise.
console.log(
`[ERROR] fetchUser failed for userId: ${userId} at ${new Date().toISOString()}`,
);Tagged Template Literals (Advanced): This is a feature most developers don't know exists. You can prefix a template literal with a function name, which intercepts the string before it's assembled. Libraries use this for SQL query sanitization, styled components, and internationalization.
function highlight(strings, ...values) {
return strings.reduce((result, str, i) => {
return result + str + (values[i] ? `<mark>${values[i]}</mark>` : "");
}, "");
}
const term = "modules";
const output = highlight`Learn about ${term} in JavaScript`;
// "Learn about <mark>modules</mark> in JavaScript"Tagged Template Flow:
highlight`Learn about ${term} in JavaScript`
↓
strings: ["Learn about ", " in JavaScript"]
values: ["modules"]
↓
Custom function processes both arrays
↓
Returns: "Learn about <mark>modules</mark> in JavaScript"The styled-components library is built entirely on this mechanism: styled.div`color: red;` is a tagged template literal call.
Key Takeaways
- String concatenation with
+doesn't scale. Template literals replace it cleanly. - Backticks enable
${}interpolation: any JavaScript expression can live inside. - Multi-line strings just work. No
\n, no line continuation hacks. - The
${}block is not limited to variables: ternaries, function calls, math, all valid. - Tagged templates are the advanced layer: they let functions intercept and transform string construction. Worth knowing they exist even if you don't use them daily.
Template literals are one of those ES6 features you adopt once and immediately wonder how you lived without. The readability improvement alone justifies the switch. And once you understand tagged templates, you start recognizing them everywhere in the ecosystem.