Getting Started with Template Literals In JavaScript

Updated on · 8 min read
Getting Started with Template Literals In JavaScript

Template literals, also known as template strings, are a powerful feature introduced in ECMAScript 2015 (ES6) that allows for more flexible and expressive string formatting in JavaScript. Unlike traditional string literals enclosed in single or double quotes, template literals are enclosed in backticks and support interpolation and multiline strings.

These literals have become an essential tool for developers, enabling them to write cleaner and more readable code. In this post, we will explore the mechanics of template literals, their syntax, and demonstrate their various use cases in JavaScript programming.

Basic syntax and usage

Historically, JavaScript strings were limited to single and double quotation marks, which could not span across multiple lines without explicit concatenation. Developers were forced to use the plus (+) operator or the concat() method to create lengthy or dynamically constructed strings. This often resulted in code that was cumbersome and difficult to read, especially when the strings incorporated variables or when formatting was crucial. For example, constructing a sentence or a block of HTML with mixed content, such as variables or user input, could quickly become a complex task, riddled with potential errors.

Template literals in JavaScript offer a straightforward syntax that differs from traditional string literals. They are enclosed within backticks (`), allowing for more flexibility and functionality compared to single or double quotes. The introduction of this feature has significantly reduced the complexity associated with string concatenation and manipulation, practices that were once cumbersome and a common source of errors.

To create a basic template literal, simply enclose the desired string content within backticks. For example:

javascript
const name = "John"; const greeting = `Hello, ${name}!`; console.log(greeting); // Output: Hello, John!
javascript
const name = "John"; const greeting = `Hello, ${name}!`; console.log(greeting); // Output: Hello, John!

In this example, the ${name} syntax is used for string interpolation, allowing the variable name to be dynamically inserted into the string.

Template literals also support multiline strings without the need for explicit newline characters. For instance:

javascript
const multilineString = ` This is a multiline string. It can span multiple lines without the need for explicit newline characters. `; console.log(multilineString); // Output: This is a multiline string. // It can span multiple lines // without the need for explicit newline characters.
javascript
const multilineString = ` This is a multiline string. It can span multiple lines without the need for explicit newline characters. `; console.log(multilineString); // Output: This is a multiline string. // It can span multiple lines // without the need for explicit newline characters.

This feature simplifies the creation of complex strings, especially for scenarios involving multiline text such as HTML templates or SQL queries.

Benefits of using template literals

Template literals offer several compelling advantages over the traditional string construction methods in JavaScript. These benefits not only lead to more readable and concise code but also to a more streamlined development process.

Improved readability

The clarity of code is significantly enhanced with template literals. The use of backticks and embedded expressions means that developers can write strings that are closer to natural language, which is particularly useful when the string content includes variables or expressions. The need for concatenation with the + operator is radically reduced, if not eliminated, making templates much easier to read and understand at a glance.

Compared to the old approach that can look clunky and be more difficult to follow:

javascript
var user = "Bob"; var message = "Hello, " + user + "! Welcome to our website!"; console.log(message); // Output: "Hello, Bob! Welcome to our website!"
javascript
var user = "Bob"; var message = "Hello, " + user + "! Welcome to our website!"; console.log(message); // Output: "Hello, Bob! Welcome to our website!"

The template literal version is more concise and readable:

javascript
const user = "Bob"; const message = `Hello, ${user}! Welcome to our website!`; console.log(message); // Output: "Hello, Bob! Welcome to our website!"
javascript
const user = "Bob"; const message = `Hello, ${user}! Welcome to our website!`; console.log(message); // Output: "Hello, Bob! Welcome to our website!"

Multiline strings

One of the most notable improvements template literals bring to JavaScript is the ability to create multiline strings effortlessly. Previously, developers had to include newline characters (\n), and use concatenation or array joins to manage multiple lines in a string. Now, text can be spread over several lines within the backticks, with the resulting string preserving the intended line breaks, greatly simplifying the creation of formatted text blocks.

Before ES6, creating a multiline string could look something like this:

javascript
var address = "Street: " + street + "\n" + "City: " + city + "\n" + "Zip Code: " + zipCode;
javascript
var address = "Street: " + street + "\n" + "City: " + city + "\n" + "Zip Code: " + zipCode;

With template literals, this becomes more natural and easier to manage:

javascript
const address = `Street: ${street} City: ${city} Zip Code: ${zipCode}`; console.log(address); // Output: // Street: 123 Main St // City: Anytown // Zip Code: 12345
javascript
const address = `Street: ${street} City: ${city} Zip Code: ${zipCode}`; console.log(address); // Output: // Street: 123 Main St // City: Anytown // Zip Code: 12345

Expression interpolation

Perhaps the most powerful feature of template literals is expression interpolation. Within a template literal, any valid JavaScript expression, when surrounded by ${} syntax, is evaluated, and the resulting value is seamlessly integrated into the string. This makes complex constructions, such as including calculated values, inserting variables, or even function calls within a string, much more straightforward and less error-prone than concatenating multiple strings together.

Consider creating a full sentence that includes a mathematical operation:

javascript
var price = 19.99; var taxRate = 0.08; var total = price + price * taxRate; var message = "The total price is: $" + total.toFixed(2);
javascript
var price = 19.99; var taxRate = 0.08; var total = price + price * taxRate; var message = "The total price is: $" + total.toFixed(2);

With template literals, the entire operation can be neatly placed within the string:

javascript
const price = 19.99; const taxRate = 0.08; const message = `The total price is: $${(price + price * taxRate).toFixed(2)}`; console.log(message); // Output: "The total price is: $21.59"
javascript
const price = 19.99; const taxRate = 0.08; const message = `The total price is: $${(price + price * taxRate).toFixed(2)}`; console.log(message); // Output: "The total price is: $21.59"

Expression interpolation is more than a convenience — it brings about a qualitative change in writing JavaScript code. It allows for the composition of dynamic strings with an elegance and simplicity that was not previously possible, and this interpolation is done in a way that is automatically secure. Special characters within expressions are properly escaped, reducing the risk of injection attacks, a common concern in web development.

These benefits collectively serve to make code not only cleaner and more maintainable but also more secure and robust. As a result, template literals are seen as an indelible part of modern JavaScript coding practices, embraced by the development community for their versatility and user-friendliness.

Advanced use cases and features

Template literals offer a range of advanced features that extend their functionality beyond simple string interpolation. These features include tagged template literals, raw strings, and the ability to nest template literals within other template literals. These capabilities provide developers with a powerful toolset for creating complex and dynamic strings in JavaScript.

Tagged template literals

Beyond simple interpolation, tagged template literals offer an advanced feature where a function processes a template literal. The tag, which is a function name placed before the template literal, receives the string parts and expressions as arguments:

javascript
function highlight(strings, ...values) { return strings.reduce((result, string, i) => { return `${result}${string}<strong>${values[i] || ""}</strong>`; }, ""); } const name = "JavaScript"; const version = "ES6"; const sentence = highlight`Learning ${name} with its new features in ${version} can be exciting.`; console.log(sentence); // Output: "Learning <strong>JavaScript</strong> with its new features in <strong>ES6</strong> can be exciting."
javascript
function highlight(strings, ...values) { return strings.reduce((result, string, i) => { return `${result}${string}<strong>${values[i] || ""}</strong>`; }, ""); } const name = "JavaScript"; const version = "ES6"; const sentence = highlight`Learning ${name} with its new features in ${version} can be exciting.`; console.log(sentence); // Output: "Learning <strong>JavaScript</strong> with its new features in <strong>ES6</strong> can be exciting."

Tag functions like highlight can be used for various purposes, such as sanitizing input, localization, styled components, and more. They provide a customizable parsing method that can interpret the parts of a template literal in unique and powerful ways. Their utility extends into TypeScript, where they can be used to create custom string literal types.

For more details on tagged template literals, see the post Advanced String Manipulation with Tagged Templates In JavaScript and MDN Web Docs.

Raw string access with template literals

Template literals provide access to unescaped strings through the raw property, which is a feature of the first argument passed to a tag function when working with tagged template literals. This allows developers to handle strings that include escape characters without processing them.

The raw strings can be particularly useful in scenarios where content should not be interpreted, such as regular expressions or when working with domain-specific languages within a JavaScript context. Here's an example of how the raw property can be leveraged:

javascript
function showRaw(strings) { const rawString = strings.raw[0]; console.log(rawString); } showRaw`This is a text with a newline character \n and a tab \t.`; // Output: "This is a text with a newline character \n and a tab \t."
javascript
function showRaw(strings) { const rawString = strings.raw[0]; console.log(rawString); } showRaw`This is a text with a newline character \n and a tab \t.`; // Output: "This is a text with a newline character \n and a tab \t."

In the example above, the typical interpretation of \n and \t as newline and tab characters respectively is not performed. Instead, the literal backslashes are maintained in the raw output.

Raw strings ignore all escape sequences and treat backslashes as simple text characters. This is how you would use raw strings to define a regular expression without doubling backslashes:

javascript
// Pattern for matching a number with two decimal places const regexPattern = String.raw`^\d+\.\d{2}$`; const regex = new RegExp(regexPattern); console.log(regex.test("123.45")); // Output: true
javascript
// Pattern for matching a number with two decimal places const regexPattern = String.raw`^\d+\.\d{2}$`; const regex = new RegExp(regexPattern); console.log(regex.test("123.45")); // Output: true

Typically, in a standard string literal, developers would need to double every backslash to escape them, which can be cumbersome and error-prone, especially in complex patterns:

javascript
const regexPattern = "^\\d+\\.\\d{2}$"; // Double backslashes are needed const regex = new RegExp(regexPattern);
javascript
const regexPattern = "^\\d+\\.\\d{2}$"; // Double backslashes are needed const regex = new RegExp(regexPattern);

By utilizing raw strings, developers can write strings that are closer to their intended form, improving legibility and reducing the risk of introducing errors that escape sequences might cause.

Nesting template literals within one another

An often overlooked feature of template literals is their ability to be nested. This allows developers to create complex strings by embedding a template literal inside another, which can be useful for constructing hierarchical or conditional text structures.

Nesting template literals becomes particularly advantageous when dealing with multiple layers of data or when creating strings based on certain conditions. Here's a simple example of nesting template literals:

javascript
const user = { name: "Bob", details: { age: 25, location: "London", }, }; const greeting = `Hello, ${user.name}! ${ user.details.age ? `You are ${user.details.age} years old. ` : "" }Welcome to ${user.details.location}.`; console.log(greeting); // Output: "Hello, Bob! You are 25 years old. Welcome to London."
javascript
const user = { name: "Bob", details: { age: 25, location: "London", }, }; const greeting = `Hello, ${user.name}! ${ user.details.age ? `You are ${user.details.age} years old. ` : "" }Welcome to ${user.details.location}.`; console.log(greeting); // Output: "Hello, Bob! You are 25 years old. Welcome to London."

In this example, a conditional check is performed inside the nested template literal to determine if the user's age should be included in the greeting.

Nesting template literals can also be used in more complex scenarios, such as in generating HTML structures or when working with component-based frameworks where the content may depend on multiple levels of data passed as properties or state:

javascript
const shoppingList = ["Apples", "Oranges", "Milk"]; const shoppingListHtml = ` <ul> ${shoppingList.map((item) => `<li>${item}</li>`).join("")} </ul> `; console.log(shoppingListHtml); // Output: // <ul> // <li>Apples</li> // <li>Oranges</li> // <li>Milk</li> // </ul>
javascript
const shoppingList = ["Apples", "Oranges", "Milk"]; const shoppingListHtml = ` <ul> ${shoppingList.map((item) => `<li>${item}</li>`).join("")} </ul> `; console.log(shoppingListHtml); // Output: // <ul> // <li>Apples</li> // <li>Oranges</li> // <li>Milk</li> // </ul>

In the above HTML generation example, a template literal is used within a .map() method callback and then embedded within another template literal to form the complete HTML list structure.

Nesting facilitates the construction of dynamic strings from sub-components, allowing each sub-component to be independently managed and composed. The seamless integration of nested template literals effectively minimizes the complexity and improves the maintainability of the code, making it a powerful pattern in JavaScript's string manipulation capabilities.

Security considerations

Alongside their syntactic convenience, template literals also bring some security benefits that are particularly relevant in web development. When using template literals, special characters in variables or expressions are automatically escaped, reducing the risk of common web vulnerabilities such as cross-site scripting (XSS) attacks.

However, it is important to note that template literals in themselves do not prevent all security risks. For instance, when creating strings from user input, developers must still be careful to sanitize and validate the input to prevent security issues. Here's an example of how template literals can be used safely:

javascript
const userProvidedInput = "<script>alert('Hacked!');</script>"; const message = `User input was: ${userProvidedInput}`; console.log(message); // Potentially dangerous if rendered in HTML without proper escaping
javascript
const userProvidedInput = "<script>alert('Hacked!');</script>"; const message = `User input was: ${userProvidedInput}`; console.log(message); // Potentially dangerous if rendered in HTML without proper escaping

To enhance security, developers should apply the principles of input validation and output encoding. While the use of template literals ensures that the string literal itself is treated as literal text, any HTML rendering still needs to consider the security context:

javascript
const userProvidedInput = "<script>alert('Hacked!');</script>"; const safeInput = sanitizeUserInput(userProvidedInput); // A function that sanitizes input const message = `User input was: ${safeInput}`; // Now, rendering `message` is safer because `safeInput` is sanitized.
javascript
const userProvidedInput = "<script>alert('Hacked!');</script>"; const safeInput = sanitizeUserInput(userProvidedInput); // A function that sanitizes input const message = `User input was: ${safeInput}`; // Now, rendering `message` is safer because `safeInput` is sanitized.

Even though JavaScript does not automatically sanitize dynamic content within template literals, it does make the job of output encoding easier by avoiding accidental syntax errors caused by quotes in strings. Ultimately, the use of template literals, coupled with diligent sanitization practices, can contribute to more secure JavaScript applications.

Conclusion

The introduction of template literals has significantly overhauled the way strings are created and manipulated in JavaScript, offering an impressive range of capabilities that extend beyond mere aesthetics. With features such as improved readability through clear syntax, support for multiline strings, and the power of expression interpolation, template literals have become an indispensable tool in modern JavaScript development.

The practical applications of template literals, such as creating dynamic strings, embedding expressions, and utilizing tagged templates, have illustrated their flexibility and effectiveness in various coding scenarios. The ability to nest template literals has introduced a new level of composability to string manipulation, enabling developers to build complex strings in an elegant and maintainable manner.

References and resources