Template literals are one of the most powerful features introduced in ES6 (ECMAScript 2015). They make working with strings in JavaScript more intuitive and flexible. When combined with tagging, they become even more versatile. In this post, we’ll explore how template literals work, the difference between untagged and tagged versions, and how to leverage tagged template literals with a practical example.
Untagged Template Literals: The Basics
Before diving into tagged template literals, let’s start with the basics: untagged template literals. These are strings enclosed in backticks (`
) instead of single or double quotes. They allow you to embed expressions directly within the string using ${}
syntax.
Here’s a simple example:
javascriptconst name = "Alice";
const greeting = `Hello, ${name}! How are you today?`;
console.log(greeting); // Output: "Hello, Alice! How are you today?"
In this case:
- The string is written between backticks.
-
${name}
is an expression placeholder that gets replaced with the value of thename
variable. - The result is a single, concatenated string.
Untagged template literals also support multi-line strings without needing special characters like \n
:
javascriptconst message = `
This is line 1.
This is line 2.
`;
console.log(message);
Output:
This is line 1.
This is line 2.
Untagged template literals are great for simple string interpolation, but they don’t give you control over how the strings and values are processed. That’s where tagged template literals come in.
Tagged Template Literals: Adding Functionality
A tagged template literal is a template literal preceded by a function name (the “tag”). The tag function processes the string parts and the embedded values before returning a result. This allows you to customize how the strings and values are handled.
How It Works
When you use a tagged template literal, JavaScript:
- Splits the template into an array of static string parts (the literal text).
-
Collects the dynamic values (the expressions in
${}
) into a separate list. - Passes these to the tag function as arguments.
The tag function receives:
- The first argument: an array of the static string parts.
- The remaining arguments: the values of the expressions, in order.
Let’s create a simple tagged template literal example:
javascriptfunction simpleTag(strings, ...values) {
console.log("Strings:", strings);
console.log("Values:", values);
return "Tagged output";
}
const a = 5;
const b = 10;
const result = simpleTag`The sum of ${a} and ${b} is ${a + b}.`;
console.log(result);
Output:
Strings: [ 'The sum of ', ' and ', ' is ', '.' ]
Values: [ 5, 10, 15 ]
Tagged output
Here’s what happens:
-
strings
is an array containing the static parts:"The sum of "
," and "
," is "
, and"."
. -
values
contains the evaluated expressions:5
,10
, and15
(froma
,b
, anda + b
). -
The function returns
"Tagged output"
, but it could manipulate the strings and values however we want.
Notice that the strings
array always has one more element than the values
array if there are expressions, because it includes the text before, between, and after the expressions.
Practical Example: Building a Dictionary with Tagged Template Literals
Now let’s look at a more practical use case. Suppose we want to create a dictionary of English-to-Turkish translations using a tagged template literal. Here’s the code:
javascriptfunction dictionary(strings, ...values) {
const map = new Map();
for (let i = 0; i < values.length; i++) {
map.set(strings[i].trim(), String(values[i]).trim());
}
return map;
}
const EnglishTurkishTranslations = dictionary`
hello ${"merhaba"}
how are you ${"nasılsın"}
yes ${"evet"}
no ${"hayır"}
can you pass the salt ${"tuzu uzatabilir misin"}
`;
console.log(EnglishTurkishTranslations);
Output
Map(5) {
'hello' => 'merhaba',
'how are you' => 'nasılsın',
'yes' => 'evet',
'no' => 'hayır',
'can you pass the salt' => 'tuzu uzatabilir misin'
}
How It Works
-
String Parts (
strings
):- The
strings
array contains the static text before each expression:["hello ", "how are you ", "yes ", "no ", "can you pass the salt ", ""]
. - The last element is an empty string because the template ends after the final expression.
- The
-
Values (
values
):- The
values
array contains the expressions:["merhaba", "nasılsın", "evet", "hayır", "tuzu uzatabilir misin"]
.
- The
-
Processing in the
dictionary
Function:- The function creates a new
Map
to store key-value pairs. - It iterates over the
values
array, using the correspondingstrings[i]
as the key andvalues[i]
as the value. .trim()
removes extra whitespace from both the keys and values for cleaner output.- The result is a
Map
where each English phrase is mapped to its Turkish translation.
- The function creates a new
Using the Dictionary
You can now use this Map
like this:
javascriptconsole.log(EnglishTurkishTranslations.get("hello")); // "merhaba"
console.log(EnglishTurkishTranslations.get("yes")); // "evet"
Why Use Tagged Template Literals?
Tagged template literals shine when you need to:
- Process strings and values in a custom way (e.g., sanitizing input, formatting, or building data structures like our dictionary).
- Create domain-specific languages (DSLs) within JavaScript.
- Improve readability for complex string manipulations.
In our dictionary example, the tagged template literal makes the translation pairs visually clear and concise, while the dictionary
function handles the logic behind the scenes.
Conclusion
Template literals are a fantastic tool in JavaScript, and tagging them takes their power to the next level. Untagged template literals are perfect for simple interpolation, while tagged template literals let you define custom behavior. Whether you’re building a translation dictionary, formatting text, or experimenting with creative syntax, tagged template literals offer a flexible and expressive solution.
Try experimenting with your own tag functions to see what you can create!
Album of the day: