Template Literals and Tagged Templates

The ES6 spec blessed us with a new string superpower. Strings are already pretty lucky. Developers can use single quotes or double quotes to wrap around a string. (Some languages only get half that many options!) So what need is there for another (apparent) string wrapper?

Template Literals

Template Literals solve a couple thorny issues with traditional strings. Whether you wrap a string in single or double quotes, it’s still a static line of text.

Let’s create a variable called name and give it a string value.

const name = 'Miles Rausch';

Now, let’s create a variable called greeting that uses our name variable. Before template literals, we may have done this:

const greeting = 'Hello, ' + name; // 'Hello, Miles Rausch'

This is… fine. It’s not great, but it’s workable. I mean, for literally decades it was good enough, but it has its awkward moments. Like when you have a lot of interpolation you want to do:

const longGreeting = 'I wanted to say, "' + greeting + '." But I instead said, "' + greeting + ', my good fellow."'; // I wanted to say, "Hello, Miles Rausch." But I instead said, "Hello, Miles Rausch, my good fellow."

It works, but it’s not readable, and it’s very easy to get off by a quote and end up in a bad state.

Let’s rewrite the above example using template literals. Instead of a single or double quote, you use a backtick or grave accent character (`). Then wrap any variables in ${} (allowing some handy string interpolation). You’ll see below.

const longGreeting = `I wanted to say, "${greeting}." But I instead said, "${greeting}, my good fellow."`; // I wanted to say, "Hello, Miles Rausch." But I instead said, "Hello, Miles Rausch, my good fellow."

So much clearer! So much nicer! I can immediately see my variables from my static text. I can also use any quotes I want without worrying about nesting. Those interpolation blocks can allow any sort of JavaScript processing, too, so I could do something like ${3 + 4} to render 7.

Talk about super powers. Template literals also support multiple lines of text.

const multiLineGreeting = `Oh, hello there.

How are you?`

But wait, there’s more!

Tagged Templates

Template literals are very useful and long overdue. They save developers time and help prevent errors. However, there is another cool feature as part of this functionality.

Let’s say you wanted to encapsulate some string manipulation. Maybe you want an easy way to make a string uppercase and begin and end the string with exclamation marks. You can write a function:

function loud(input) {
    return `!! ${input.toUpperCase()} !!`;
}
const loudGreeting = loud('Hi, there'); // !! HI, THERE !!

This technique works just fine, but we can take advantage of the new tagged templates spec to improve readability. With tagged templates, you simply prefix the template literal with the name of the function and ensure your function follows a specific interface. Let’s rewrite the function and variable assignment using tagged templates.

function loud(inputArray) {
    return `!! ${inputArray[0].toUpperCase()} !!`;
}
const loudGreeting = loud`Hi, there`; // !! HI, THERE !!

We may have only saved two characters, but there’s more to this superpower. Did you notice that the input this time was an array? inputArray is an array of strings around each interpolation. In our simple example, we had no interpolation. If we had included interpolation, our function wouldn’t have been as useful, because we didn’t account for interpolation values.

const loudGreeting = loud`He said, "${greeting}"`; // !! HE SAID, " !!

Also passed into the function are all the interpolations, sent as parameters in the order they appear in the string. If your tag function has a highly specific use case, you can name these parameters. However, it’s usually better to use the ES6 rest parameter to bundle them into an array.

function tagFunction(inputArray, ...values) { ... }

Taking Templates Further

This separation allows for some interesting scenarios. Any time where you’d want to treat dynamic content differently from static content, a tagged template could come in handy.

Think translations. You want the static text in the string to get translated but the interpolated values to remain untouched. Tagged templates do this separation automatically for you and give you a nice syntax for using it. Here’s a completely unsophisticated Spanish translator:

function toES(toTranslate, ...values) {
  const dictionary = {
    'Hello': 'Hola'
  };
  
  return toTranslate.reduce((translation, item, index) => {
    const key = item.replace(/\s+/g, '');
    const newItem = item.replace(key, dictionary[key] || key);
    
    translation += `${newItem}${values[index] || ''}`;
    
    return translation;
  }, '');
}

const spanishGreeting = toES`Hello ${name}!`; // Hola Miles!

You don’t have to return just strings, either. Libraries like styled-components use the finesse of tagged template syntax to return styled React components. Creating a styled <Title /> component is as easy as:

const Title = styled.h1`
  font-size: 1.5em;
  text-align: center;
  color: palevioletred;
`;

<Title>Hello World!</Title>

Give template literals and tagged templates a try today!


%d bloggers like this: