Advanced JavaScript ES2015 Template Strings with Tagged Templates

Follow us on LinkedIn for our latest data and tips!

If you’ve paid any attention to the discussions about ES2015/ES6 that have been going on over the past couple years, you should already know about template literal strings:

`This string starts and ends with a backtick and can have expressions, e.g. 5 + 5 = ${5+5}.

It can also have multiple lines without any odd "hacks".`

This in itself is an extremely useful tool that can simplify how we work with strings dramatically, but there is a little-known feature that came along with the template strings that can take them to an entirely different level of usefulness: tagged template literals.

Tagged Template Literals

A tagged template literal is a template literal (as you’ve already seen) that is preceded by a tag. A tag is a function that receives all the pieces of the string that you created via the template literal and returns something that should be based on the string. Here’s a simple (and incomplete) example to help you understand:

// Some dummy data... just I just call myself a dummy?
let user = {
    firstName: "Joseph",
    lastName: "Zimmerman",
    nickname: "Zim"

// Define the tag (definitely doesn't need to be called "tag")
function tag (...args) {
    // do something with those args
    // return something

// prefix with `tag` and foo will be set to whatever tag returns
let foo = tag`My name is ${user.firstName} ${user.lastName}, but my friends call me ${user.nickname}.`

This looks very strange to those who aren’t acclimated. You wouldn’t put the name of a function right in front of any old string (e.g. myFunc"a string") and expect anything to happen other than a syntax error, right? Well, it works just fine with template strings. The interesting thing here is that it ends up being a function call without using any parenthesis. Things are just getting weirder by the second!

So the next question on your mind is probably, “what arguments does the tag function get called with?”, right? Well, that’s what I was wondering when I first looked at these, so that’s what we’ll look at next. The first argument is an array of each of the pieces of the string that aren’t template substitutions (the expressions surrounded by ${ ... }) . The rest of the arguments are each of the template substitution values.

Once again, I think an example will help explain things:

function tag (stringBits, val1, val2) {
    console.log(stringBits) // => ["My name is ", " ", "."]
    console.log(val1) // => "Joseph"
    console.log(val2) // => "Zimmerman"

tag`My name is ${user.firstName} ${user.lastName}.`

I’m a little disappointed that you only see the interpolated values of the expressions and that there’s no way to get access to the literal expression so that the tag functions can allow an additional way of handling the interpolation. I’m sure there’s a good reason, such as confusing developers when the expressions don’t end up as the same value they expected.

Anyway, as you can see, all of the string parts show up as an array for the first argument. Even if there’s no characters between certain parts of the string, you’ll end up getting empty strings in that array, For example:

function tag(stringBits) {
    console.log(stringBits) // => ["test", "", ""]


See how we received 2 empty strings in that array. The first one is the characters between the two expressions and the second one is at the end of the string, after the second expression.

Also, not that every interpolated value is passed into the tag function as a separate arguments. This would be a big pain in the rear end, but since we’re using ES2015 anyway, we can use rest parameters to group all of those arguments into an array, like this.

function tag (stringBits, ...values) {
    console.log(stringBits) // => ["My name is ", " ", "."]
    console.log(values) // => ["Joseph", "Zimmerman"]

tag`My name is ${user.firstName} ${user.lastName}.`

I can’t foresee any situations where this wouldn’t be the preferred way of handling those values, so we’ll stick to using the rest parameter from now on.

One last thing to note: I haven’t been completely honest about the value of stringBits (the first parameter of the tag function) in these examples. You see, stringBits is more than just an array; it also has a raw property, which is also an array of the string pieces. There’s a difference, though: if you have escaped characters in your string (e.g. "\n"), it’ll be converted to a new line in the main array, but in the raw array, it’ll show up just as you typed it, as if you had actually used "\\n". Check out the example below:

let place = "world"

function tag (stringBits, ...values) {

tag`Hello ${place}.\nWelcome to this tutorial.`

The Chrome console would output something like this:

    0: "Hello ",
    1: ".↵Welcome to this tutorial.",
    length: 2
    raw: Array[2]
        0: "Hello ",
        1: ".\nWelcome to this tutorial"
        length: 2

See how in the main array there is a "↵" representing the new line, whereas in the raw array we still see the "\n". If you’re looking for the raw characters that the developer writes then this can be useful. It’s also worth noting, though, that if you simply want to create a tag so that you can get the raw string, then don’t waste your time. There is a built-in tag for that: String.raw.

String.raw`Hello ${place}.\nWelcome to this tutorial.`
// => "Hello world.\nWelcome to this tutorial."

Just as a quick exercise, let’s recreate the normal template literal behavior with our own tag function:

function tag(strings, ...values) {
    return strings.reduce(function(combined, string, i) {
        return combined + string + values[i]
    }, "")

Turns out it’s as simple as strings[0] + values[0] + strings[1] + values[1]..., which we accomplish with reduce so that we don’t need to worry about how many parts are in the string.


So what kind of applications are there for this? How can you use tagged template literals in a helpful way? Well, I couldn’t think of anything special, but some others in the community have. The first example is html-tagged-template, which allows you to feed a string of HTML into it, and the tag will actually spit out DOM nodes that match your HTML.










This will return the entire hierarchy of DOM nodes without resorting to innerHTML nonsense or a ton of node creation and appending. I’d check out the project to see how it might help you, though something like React’s JSX might be a better solutions because a lot of the parsing is handled by the pre-processor rather than the browser.

Speaking of React, there is another powerful use for tagged template literals called styled-components that simplifies how you create base components and style them by allowing you to just specify the CSS as a template literal to the tag from styled-components. For example:

import React from 'react';
import styled from 'styled-components';

// Create a <Title> react component that renders an <h1> which is centered, palevioletred and sized at 1.5em
const Title = styled.h1`
  font-size: 1.5em;
  text-align: center;
  color: palevioletred;

// Create a <Wrapper> react component that renders a <section> with some padding and a papayawhip background
const Wrapper = styled.section`
  padding: 4em;
  background: papayawhip;

function HelloWorld () {
  return (
      <Title>Hello World, this is my first styled component!</Title>

export default HelloWorld;

This gives you a few React components:

  • Title, which is an H1 tag styled with the CSS provided in the template literal string
  • Wrapper, which is a SECTION tag styled with the CSS provided in the template literal string.
  • HelloWorld, which composes the other two components

You can go here to see this in action and fiddle around with it. Of course, you’re not obligated to try it; I just wanted to give you some examples of how tagged template literals can be used to do some powerful things. If you have any questions about tagged template literals or interesting ideas of how you could use them, drop them in the comments.