DEV Community

Rafael Leitão
Rafael Leitão

Posted on

Understanding Tagged Template Literal in JS

Hello everyone! 👋

Recently, I have been building some components around using the styled-component library and I was curious about how it worked behind the curtains, specially because of the use of backticks (``) to create the components. Looking at the library docs, I found a link to this awesome article The magic behind 💅 styled-components,written by Max Stoiber, and learned that Tagged Template Literals are a essencial to it.

So, I decided to understand a bit more about it, to try to mock its behaviour with some components I built and to share what I learned here, in case it will be useful for anyone in the future.

Okay, but first: What is Template Literal?

Template Literals

The ES6 introduced the template literals which are a new way to create strings allowing embedded expressions, string interpolations, multiline strings and HTML templates. To use it, we use backticks (``) instead of single or double quotes as in regular strings.

It can contain placeholders, specified by the ${}, that take any valid Javascript expression inside it to make string substitution with the result.

Comparing to the "old" way, this give us handy benefits like:

// They all produce the same result
const firstName = 'Jonh'
const lastName = 'Doe'

console.log('My name is ' + firstName + ' ' + lastName)
console.log(`My name is ${firstName} ${lastName}`)

const oldMultiline = 'I want the\nold two lines!'
const newMultiline = `I want the
new two lines!`


Enter fullscreen mode Exit fullscreen mode

Cool, but what about the Tagged Template Literals?

Tagged Template Literals

They are a more advanced form of template literals which allow us to parse template literals with a function, giving us more control over how we want this string to be parsed.

The Tagged in the name is because the template literal was "tagged" with the function, which is now called the tag function. To have a Tagged Template Literal, we simply call a function with the template literal after the function name but without parentheses.

const tagFunction = (sentence) => console.log(sentence)

// Tagged function call
tagFunction`This template literal has been tagged`

// Normal function call
tagFunction(`This template literal has NOT been tagged`)
Enter fullscreen mode Exit fullscreen mode

Alt Text

But from there, we start seeing the differences from a normal function call. The function itself is just like any other, but what it receives as parameter is different depending on whether we call it as a tagged template literal or not.

When calling as tagged template literal, the tag function will receive an array of strings from the template literal as its first argument instead of the string itself.

Okay, fair enough... but what if we have an ${} with an expression in the template literal?

This is when it gets interesting!

Tagged Template Literals with embedded expressions

When we add embedded expressions in the template literal and pass it to the function as tagged template literal, we get more parameters depending on how many expressions we passed. In this case, the first parameter will be an array of strings spliced based on the expressions positions in the template string and the remaining parameters will be the evaluated expressions.
Hhmm, sounds a bit complicated, right? Let's see how it is not in the snippet below:

const tagFunction = (sentenceParts, firstName, lastName, age) => console.log(sentenceParts, firstName, lastName, age)

const firstName = 'Jonh'
const lastName = 'Doe'
const age = 36

// Tagged function call
tagFunction`My first name is ${firstName} and last name is ${lastName} and I am ${age - 9} years old.`

// Normal function call
tagFunction(`My first name is ${firstName} and last name is ${lastName} and I am ${age - 9} years old.`)
Enter fullscreen mode Exit fullscreen mode

Alt Text

As you can see from the logs, when calling as tagged template literal, the tagFunction receives the first parameter as the array of strings and the other parameters as the ${expression} already evaluated. Also note that, when calling tagFunction as a normal function we only get the first argument, with the embedded expressions evaluated, since we don't pass any other.

Since we may not know how many embedded expressions it's going to be passed to our tagFunction, it's recommended that we use the rest operator to gather all the remaining parameters in an array.

// It produces the same log as the previous tagged template literal call
const tagFunction = (sentenceParts, ...separations) => console.log(sentenceParts, ...separations)

Enter fullscreen mode Exit fullscreen mode


Just to finish with a closer example of a real use we can see the example below. The toUpper function receives the strings array and the embedded expressions and returns the expressions with upper case letters.

const toUpper = (sentenceParts, ...expressions) => {
    const parsed = sentenceParts.reduce((previous, current, i) => {
        return `${previous}${current}${expressions[i] ? expressions[i].toUpperCase() : ''}`
    }, '')
    return parsed

const firstName = 'jonh'
const lastName = 'doe'

toUpper`My name is ${firstName} ${lastName}`

// This produces => "My name is JONH DOE"
Enter fullscreen mode Exit fullscreen mode


Tagged Template Literals are a powerful feature that give us another option on how to parse strings in different ways. With them, the tag function receives the parts of the template literal as the first argument and the embedded expressions as subsequent arguments so then you can decide how to determine the final output of your string.

This features is so powerful that some awesome libraries were built on it such as Styled Components and graphql-tag.

That's it! Hopefully this article was helpful for you to undestand a bit more about Tagged Template Literals.


This post would not be possible without other articles from awesome developers out there. If you want check what helped my learning, click on the links below:

Top comments (0)