\n
)String.raw
ES6 has two new kinds of literals: template literals and tagged template literals. These two literals have similar names and look similar, but they are quite different. It is therefore important to distinguish:
Template literals are string literals that can stretch across multiple lines and include interpolated expressions (inserted via ${···}
):
Tagged template literals (short: tagged templates) are created by mentioning a function before a template literal:
Tagged templates are function calls. In the previous example, the method String.raw
is called to produce the result of the tagged template.
Literals are syntactic constructs that produce values. Examples include string literals (which produce strings) and regular expression literals (which produce regular expression objects). ECMAScript 6 has two new literals:
It is important to keep in mind that the names of template literals and tagged templates are slightly misleading. They have nothing to do with templates, as often used in web development: text files with blanks that can be filled in via (e.g.) JSON data.
A template literal is a new kind of string literal that can span multiple lines and interpolate expressions (include their results). For example:
The literal itself is delimited by backticks (`
), the interpolated expressions inside the literal are delimited by ${
and }
. Template literals always produce strings.
The backslash is used for escaping inside template literals.
It enables you to mention backticks and ${
inside template literals:
Other than that, the backslash works like in string literals:
\n
) Common ways of terminating lines are:
\n
, U+000A): used by Unix (incl. current macOS)\r
, U+000D): used by the old Mac OS.\r\n
): used by Windows.All of these line terminators are normalized to LF in template literals. That is, the following code logs true
on all platforms:
The following is a tagged template literal (short: tagged template):
Putting a template literal after an expression triggers a function call, similar to how a parameter list (comma-separated values in parentheses) triggers a function call. The previous code is equivalent to the following function call (in reality, first parameter is more than just an Array, but that is explained later).
Thus, the name before the content in backticks is the name of a function to call, the tag function. The tag function receives two different kinds of data:
'Hello '
.firstName
(delimited by ${}
). A substitution can be any expression.Template strings are known statically (at compile time), substitutions are only known at runtime. The tag function can do with its parameters as it pleases: It can completely ignore the template strings, return values of any type, etc.
Additionally, tag functions get two versions of each template string:
`\n`
becomes '\\n'
, a string of length 2)`\n`
becomes a string with just a newline in it).That allows String.raw
(which is explained later) to do its work:
Tagged template literals allow you to implement custom embedded sub-languages (which are sometimes called domain-specific languages) with little effort, because JavaScript does much of the parsing for you. You only have to write a function that receives the results.
Let’s look at examples. Some of them are inspired by the original proposal for template literals, which refers to them via their old name, quasi-literals.
ES6 includes the tag function String.raw
for raw strings, where backslashes have no special meaning:
This is useful whenever you need to create strings that have backslashes in them. For example:
In line A, String.raw
enables us to write the backslash as we would in a regular expression literal. With normal string literals, we have to escape twice: First, we need to escape the dot for the regular expression. Second, we need to escape the backslash for the string literal.
(Source: David Herman)
(Source: David Herman)
(Source: Luke Hoban)
Steven Levithan has given an example of how tagged template literals could be used for his regular expression library XRegExp.
Without tagged templates, you write code such as the following:
We can see that XRegExp gives us named groups (year
, month
, title
) and the x
flag. With that flag, most whitespace is ignored and comments can be inserted.
There are two reasons that string literals don’t work well here. First, we have to type every regular expression backslash twice, to escape it for the string literal. Second, it is cumbersome to enter multiple lines.
Instead of adding strings, you can also continue a string literal in the next line if you end the current line with a backslash. But that still involves much visual clutter, especially because you still need the explicit newline via \n
at the end of each line.
Problems with backslashes and multiple lines go away with tagged templates:
Additionally, tagged templates let you insert values v
via ${v}
. I’d expect a regular expression library to escape strings and to insert regular expressions verbatim. For example:
This would be equivalent to
Example:
This is a DOM query that looks for all <a>
tags whose CSS class is className
and whose target is a URL with the given domain. The tag function $
ensures that the arguments are correctly escaped, making this approach safer than manual string concatenation.
Facebook React is “a JavaScript library for building user interfaces”. It has the optional language extension JSX that enables you to build virtual DOM trees for user interfaces. This extension makes your code more concise, but it is also non-standard and breaks compatibility with the rest of the JavaScript ecosystem.
The library t7.js provides an alternative to JSX and uses templates tagged with t7
:
In “Why not Template Literals?”, the React team explains why they opted not to use template literals. One challenge is accessing components inside tagged templates. For example, MyWidget
is accessed from the second tagged template in the previous example. One verbose way of doing so would be:
Instead, t7.js uses a registry which is filled via t7.assign()
. That requires extra configuration, but the template literals look nicer; especially if there is both an opening and a closing tag.
Facebook Relay is a “JavaScript framework for building data-driven React applications”. One of its parts is the query language GraphQL whose queries can be created via templates tagged with Relay.QL
. For example (borrowed from the Relay homepage):
The objects starting in line A and line B define fragments, which are defined via callbacks that return queries. The result of fragment tea
is put into this.props.tea
. The result of fragment store
is put into this.props.store
.
This is the data that the queries operates on:
This data is wrapped in an instance of GraphQLSchema
, where it gets the name Store
(as mentioned in fragment on Store
).
This section describes a simple approach to text localization that supports different languages and different locales (how to format numbers, time, etc.). Given the following message.
The tag function msg
would work as follows.
First, The literal parts are concatenated to form a string that can be used to look up a translation in a table. The lookup string for the previous example is:
This lookup string could, for example, be mapped to a German translation::
The English “translation” would be the same as the lookup string.
Second, the result from the lookup is used to display the substitutions. Because a lookup result includes indices, it can rearrange the order of the substitutions. That has been done in German, where the visitor number comes before the site name. How the substitutions are formatted can be influenced via annotations such as :d
. This annotation means that a locale-specific decimal separator should be used for visitorNumber
. Thus, a possible English result is:
In German, we have results such as:
Let’s say we want to create HTML that displays the following data in a table:
As explained previously, template literals are not templates:
A template is basically a function: data in, text out. And that description gives us a clue how we can turn a template literal into an actual template. Let’s implement a template tmpl
as a function that maps an Array addrs
to a string:
The outer template literal provides the bracketing <table>
and </table>
. Inside, we are embedding JavaScript code that produces a string by joining an Array of strings. The Array is created by mapping each address to two table rows. Note that the plain text pieces <Jane>
and <Croft>
are not properly escaped. How to do that via a tagged template is explained in the next section.
This is a useful quick solution for smaller templating tasks. For larger tasks, you may want more powerful solutions such as the templating engine Handlebars.js or the JSX syntax used in React.
Acknowledgement: This approach to text templating is based on an idea by Claus Reinke.
Compared to using untagged templates for HTML templating, like we did in the previous section, tagged templates bring two advantages:
${}
with an exclamation mark. That is needed for the names, which contain characters that need to be escaped (<Jane>
).join()
Arrays for us, so that we don’t have to call that method ourselves.Then the code for the template looks as follows. The name of the tag function is html
:
Note that the angle brackets around Jane
and Croft
are escaped, whereas those around tr
and td
aren’t.
If you prefix a substitution with an exclamation mark (!${addr.first}
) then it will be HTML-escaped. The tag function checks the text preceding a substitution in order to determine whether to escape or not.
An implementation of html
is shown later.
The following is a tagged template literal:
This literal triggers (roughly) the following function call:
The exact function call looks more like this:
There are two kinds of input that the tag function receives:
' lit2 '
). A template object stores two versions of the template strings:
\n
interpreted. Stored in templateObject[0]
etc.templateObject.raw[0]
etc.${}
(e.g. subst1
). Substitutions are dynamic, they can change with each invocation.The idea behind a global template object is that the same tagged template might be executed multiple times (e.g. in a loop or a function). The template object enables the tag function to cache data from previous invocations: It can put data it derived from input kind #1 (template strings) into the object, to avoid recomputing it. Caching happens per realm (think frame in a browser). That is, there is one template object per call site and realm.
Let’s use the following tag function to explore how many template strings there are compared to substitutions.
The number of template strings is always one plus the number of substitutions. In other words: every substitution is always surrounded by two template strings.
If a substitution is first in a literal, it is prefixed by an empty template string:
If a substitution is last in a literal, it is suffixed by an empty template string:
An empty template literal produces one template string and no substitutions:
Template strings are available in two interpretations – cooked and raw. These interpretations influence escaping:
\
) in front of ${
prevents it from being interpreted as starting a substitution.The tag function describe
allows us to explore what that means.
Let’s use this tag function:
As you can see, whenever the cooked interpretation has a substitution or a backtick then so does the raw interpretation. However, all backslashes from the literal appear in the raw interpretation.
Other occurrences of the backslash are interpreted as follows:
For example:
To summarize: The only effect the backslash has in raw mode is that it escapes substitutions and backticks.
String.raw
The following is how you’d implement String.raw
:
I previously demonstrated the tag function html
for HTML templating:
If you precede a substitution with an exclamation mark (!${addr.first}
), it will be HTML-escaped. The tag function checks the text preceding a substitution in order to determine whether to escape or not.
This is an implementation of html
:
There is always one more template string than substitutions, which is why we need to append the last template string in line A.
The following is a simple implementation of htmlEscape()
.
There are more things you can do with this approach to templating:
cond?then:else
) or via the logical Or operator (||
):
The first non-whitespace characters are <div>
, which means that the text starts in column 4 (the leftmost column is column 0). The tag function html
could automatically remove all preceding columns. Then the previous tagged template would be equivalent to:
There are two ways of creating regular expression instances.
/^abc$/i
RegExp
constructor: new RegExp('^abc$', 'i')
If you use the latter, it is because you have to wait until runtime so that all necessary ingredients are available. You are creating the regular expression by concatenating three kinds of pieces:
For #3, special characters (dots, square brackets, etc.) have to be escaped, while #1 and #2 can be used verbatim. A regular expression tag function regex
can help with this task:
regex
looks like this:
Template literals and tagged template literals were borrowed from the language E, which calls this feature quasi literals.
Macros allow you to implement language constructs that have custom syntax. It’s difficult to provide macros for a programming language whose syntax is as complex as JavaScript’s. Research in this area is ongoing (see Mozilla’s sweet.js).
While macros are much more powerful for implementing sub-languages than tagged templates, they depend on the tokenization of the language. Therefore, tagged templates are complementary, because they specialize on text content.
What if I want to load a template literal such as `Hello ${name}!`
from an external source (e.g., a file)?
You are abusing template literals if you do so. Given that a template literal can contain arbitrary expressions and is a literal, loading it from somewhere else is similar to loading an expression or a string literal – you have to use eval()
or something similar.
The backtick was one of the few ASCII characters that were still unused in JavaScript. The syntax ${}
for interpolation is very common (Unix shells, etc.).
The template literal terminology changed relatively late during the creation of the ES6 spec. The following are the old terms: