Tagged Template Literals in JavaScript

In the blog post 8 days ago with the title “Dynamic parameters in JavaScript“, I have shown you how functions with a variable number of parameters work. Today, I want to talk about the “tagged templates” feature in JavaScript, as a form of a function with a variable number of parameters.

Template Literals

Before we head into the topic, let’s talk about template literals first. In old versions of JavaScript, you would have done the following, you place a variable in between some static text:

var name = "Bernhard";
var country = "Finland";
var greet = "Hi, my name is " + name + " and I'm currently in " + country + ".";
console.log(greet);
//Hi, my name is Bernhard and I'm currently in Finland.

With modern JavaScript, you can use a “template literals” to place some variable (or even code) inside your strings that get interpreted:

const name = "Bernhard";
const country = "Finland";
const greet = `Hi, my name is ${name} and I'm currently in ${country}.`;
console.log(greet);
//Hi, my name is Bernhard and I'm currently in Finland.

Using the backticks instead of other quotes, we turn our simple string into a template literal. Isn’t that much easier to read? Ah, and yes. I am currently in Finland, and not in Berlin. On the ร…land Islands, to be precise.

Tagged Template Literals

After this short introduction, let’s come to the “tagged” template literals. When you first see them, they might look a bit odd. This is how one example might look like:

const name = "Bernhard";
const country = "Finland";
const greet = makeItBold`Hi, my name is ${name} and I'm currently in ${country}.`;

function makeItBold(strings, ...values) {
	// strings => ['Hello, my name is ', " and I'm currently in ", '.']
	// values => ['Bernhard', 'Finland']

	let result = "";

	// Loop through the strings and values
	for (let i = 0; i < values.length; i++) {
		result += strings[i] + `<b>${values[i]}</b>`;
	}

	// Append the last string (after the last variable)
	result += strings[values.length];

	return result;
}

console.log(greet);
// Hi, my name is <b>Bernhard</b> and I'm currently in <b>Finland</b>.

We define a function (makeItBold) and then we just write the function name before the template literal. In the function, we get the “static strings array” as the first strings parameter and then a dynamic number of parameters for each “variable” (or more precisely the expressions) in the template literal as the second values parameter. We could also write this function like this:

function makeItBold(strings, name, country) {
	// ...
}

But that would not really be flexible, if we swap the variables around or have more/fewer variables in another string.

One thing we can do, to make the function a little shorter, is using some modern JavaScript code handling arrays (written in multiple lines for better readability):

function makeItBold(strings, ...values) {
	return strings.reduce(
		(result, str, i) => result + str + (values[i] ? `<b>${values[i]}</b>` : ""),
		""
	);
}

Those of you familiar with modern JavaScript can probably easily read this, I still have to look twice and read it carefully.

I had hard times finding a good “real life example”, but after coming up with the example above, I found one that might be really useful, and that is not using scalar values, but objects. What do you think about this one?

function schema(strings, ...values) {
	return strings.reduce((result, str, i) => {
		const value = values[i];
		if (value) {
			// Check for specific schema.org types and add relevant markup
			if (value.type === "Person") {
				return (
					result +
					str +
					`<span itemscope itemtype="https://schema.org/Person">
						<span itemprop="name">${value.name}</span>
					</span>`
				);
			} else if (value.type === "Place") {
				return (
					result +
					str +
					`<span itemscope itemtype="https://schema.org/Place">
						<span itemprop="name">${value.name}</span>
					</span>`
				);
			}
		}
		return result + str;
	}, "");
}

// Usage
const name = { type: "Person", name: "Bernhard" };
const country = { type: "Place", name: "Finland" };

const greet = schema`Hello, my name is ${name} and I'm currently in ${country}.`;

console.log(greet);
// Hello, my name is <span itemscope itemtype="https://schema.org/Person"><span itemprop="name">Bernhard</span></span> and I'm currently in <span itemscope itemtype="https://schema.org/Place"><span itemprop="name">Finland</span></span>.

Conclusion

As mentioned, I wasn’t easy finding a good example. One could argue, that you could also just a template literal in many cases and some inline HTML markup. But still this feature is available to you, and you should know how to read code using it.

If you have an example from one of your projects using a tagged template literal, please leave a comment.

Posted by

Bernhard is a full time web developer who likes to write WordPress plugins in his free time and is an active member of the WP Meetups in Berlin and Potsdam.

Leave a Reply

Your email address will not be published. Required fields are marked *