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!`
console.log(oldMultiline)
console.log(newMultiline)
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`)
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.`)
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)
Example
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"
Conclusion
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
.
References
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:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals
https://www.alura.com.br/artigos/tagged-template-literals
https://developers.google.com/web/updates/2015/01/ES6-Template-Strings
https://dev.to/atapas/what-exactly-is-javascript-tagged-template-literal-1h7f
https://dev.to/joelhassan/js-tagged-template-literals-26ff
https://dev.to/kannndev/tagged-template-literals-bii
https://nipher.io/es6-template-literals/
https://css-tricks.com/template-literals/
https://wesbos.com/tagged-template-literals
Top comments (0)