Read More on Telerik Blogs
December 27, 2022 Web, Angular
Get A Free Trial

Template literals are strings that provide an easy way to create multiline strings, string interpolation and even custom functions. Let’s take a look! 

Template literals are literals that are delimited with backticks (``). Template literals were introduced in ECMAScript6. They are strings with the same methods available to them as regular strings (delimited by '' or "").

let icecreamFlavour = `Strawberry`;

typeof icecreamFlavour;         			// 'string'  
icecreamFlavour.length;         			// 10  
icecreamFlavour.toUpperCase();  	// 'STRAWBERRY'


Image credit: @Dakari_Jaxtyn

In addition, template literals solve problems that we had with strings previous to ECMAScript6. Template literals provide:

  • An easy way to create multiline strings
  • String interpolation

We can also tag template literals with custom functions and provide the logic for parsing the template literals ourselves.

Let’s look at each feature in turn.

Multiline Strings

Since the introduction of template literals in ECMAScript 6, creating multiline strings is super easy. All whitespace inside the backticks in a template literal is honored as part of the string. This includes newlines and tabs without explicitly typing \n or \t.

This is especially handy when we want to define code within a string as we can use space and indentation to write code that is easy to read.

For example, Angular lets us define a component’s template and styles in a separate file or directly in the @Component decorator. Developers often prefer to keep the component’s HTML and CSS code within the component.ts file so they can see all the component’s code in one place and save switching between files.

@Component({  
    template: `  
        <h2>Icecream Orders</h2>  
  
        <ul>  
            <li *ngFor="let flavour of flavours">  
                {{ flavour }}  
            </li>  
        </ul>
    `,  
    styles: [`
        h2 {
	      background-color: lightgray;
	      padding: 5px 10px;
	    }
    `]
})  
class OrdersComponent {  
  flavours = [
	  'Liquorice and Blackcurrent', 
	  'Stem Ginger', 
	  'Lemon Meringue'
  ];
}

It is a breeze to create multiline strings using template literals — we simply type our string with all the whitespace we need within the backticks (``) .

Note also that we don’t need to escape double or single quotes within backticks, but, we do need to escape any backticks within a template literal.

let tip = `The \`<h1>\` tag is used for 'Heading 1'.`;

console.log(tip);   

// Logs:  
The `<h1>` tag is used for 'Heading 1'.

Before template literals were available, we could only use create strings using single quotes or double quotes which needs to be contained on a single line. To create multiline strings using a single or double quote we need to add backslash character ( \) at the end of each line in the string.

let order = 'Pistachio \
    Chocolate and Mint \
    Matcha';

console.log(order);

// Logs the following:  
Pistachio     Chocolate and Mint     Matcha

The \ character lets us type the string over multiple line. To print on a new line we need to include \n as well.

let order2 = 'Pistachio \n\
    Chocolate and Mint \n\
    Matcha';

console.log(order2);

// Logs the following:
Pistachio   
Chocolate and Mint   
Matcha

Or alternatively, use string concatenation (+) to type the string over multiple lines and include \n for newlines.

let order1 = 'Bubble Gum \n' +
    'Peanut Butter Jelly\n' +
    'Cotton Candy';

console.log(order1);

// logs the following:  
Bubble Gum   
Peanut Butter Jelly  
Cotton Candy

Now we’ve seen that it is really easy to create multiline strings with template literals. Let’s look at how easy it is to combine outputs from expressions to strings using template literals.

String Interpolation

The best part of template literals has to be string interpolation. We can put any valid JavaScript expression within the template literal using the “${” as opening and “}” as closing delimiters, like so: ${expression}. The expression is evaluated and the result is concatenated to the string on either side.

We can think of the ${expression} as a placeholder for the expression value when we define the template literal. When the code is executed at runtime the expression is evaluated and its resulting value is substituted into the string in place of the placeholder. Placeholder, substitution and string interpolation are synonyms for this.

The following code example illustrates that:

  • Substitutions can be any valid JavaScript expression including function calls.
  • Template literals can access variables that are within the scope.
  • Trying to access a variable that doesn’t exist in the scope gives an error.
let order = [  
    { scoops: 1, flavour: 'Maple Wallnut' },   
    { scoops: 1, flavour: 'Buttered Pecan' },   
    { scoops: 1, flavour: 'Coconut Bounty' }  
];

let numberOfScoops = order.reduce((prev, cur) => prev + cur.scoops, 0);

let receipt = `${numberOfScoops}:   
    ${order[0].scoops} ${order[0].flavour}   
    ${order[1].scoops} ${order[1].flavour}   
    ${order[2].scoops} ${order[2].flavour}`;

console.log(receipt);

// Logs the following:
3 scoops:   
    1 Maple Wallnut   
    1 Buttered Pecan   
    1 Coconut Bounty

console.log(`Flavours Available: {flavours}`);

// Gives an error as flavours is not defined  
Uncaught ReferenceError: flavours is not defined

Nesting Template Literals

We can nest template literals within a template literal.

For example, instead of hardcoding accessing the ice cream flavors from the order array, we can use the array map() method to create a nested template literal for each ice cream flavor in the order.

I initially thought of using forEach(), however forEach() returns undefined whereas map() returns an array of transformed values. After mapping, we can join our array of ice cream flavors with a template literal which has a newline and indentation — for formatting.

let order = [  
    { scoops: 2, flavour: 'White Chocolate' },  
    { scoops 1, flavour: 'Rum and Raisin'}

];

let numberOfScoops = order.reduce((prev, cur) => prev + cur.scoops, 0);

let receipt = `${numberOfScoops} ${ numberOfScoops > 1 ? 'scoops' : 'scoop' }:   
    ${order  
      .map((item) => **`${item.scoops} ${item.flavour}`**)  
      .join(`  
    `)}  
`;

console.log(receipt);

// Logs:  
"3 scoops:   
    2 White Chocolate  
    1 Rum and Raisin  
"

Notice that we can conditionally choose the expression to interpolate in our template literal. In the code above we’ve use the ternary operator to display the plural or singular form of “scoop” based on the number of ice cream scoops.

As we see, string interpolation is also a breeze with template literals! Next, let’s look at how to provide our own function for parsing template literals.

Tagged Templates

We can tag a template literal with a function that defines how to parse the template literal. The function receives an array of the string literals from the template literal as the first parameter and the interpolated values in the template literal as further arguments. The function does not have to be called tag—it can be any name that reflects the function’s purpose.

function tag(literals, ...values) {
  console.log(literals); 
  console.log(values);   
}
userName = 'Arlo';
let greeting = tag`Hi, ${userName}!`;

// Logs: 
// ["Hi, ","!"]
// ["Arlo"]

// Leaving out '!' at the end of string:
greeting = tag`Hi, ${userName}`; 
// Logs: 
// ["Hi, ",""]
// ["Arlo"]

We can see that the first parameter of the tag function is an array containing the string literals from the template literal, including any whitespace. If the template literal ends with a ${} placehoder, then the last element in the literals array is an empty string "". In this way the literals array is one longer than the values array.

If we were to repeat what the default template literal function does, we’d do something like the following code:

function parse(literals, ...values) {
  let result = '';
  
  values.forEach((value, index) => {
    result += literals[index];
    result += value;
  })
  
  let literalsLength = literals.length;
  let valuesLength = values.length;
  
  if (literalsLength > valuesLength) {
    result += literals[literalsLength - 1];
  }
  
  return result;
}
userName = 'Arlo';
let greeting = parse`Hi, ${userName}!`;
console.log(greeting); // "Hi, Arlo!"

I find it hard to think of a good use case for tagged templates, as we can achieve a lot with the default template literals. For example, if we want to transform the strings to uppercase, we can use the toUpperCase() method, we can call a function to calculate total cost, etc.

Instead, we can look at real world examples for use cases of tagged templates:

Further Reading

For further reading, please refer to these brilliant books:


About the Author

Ashnita Bali

Ashnita is a frontend web developer who loves JavaScript and Angular. She is an organizer at GDGReading, a WomenTechmakers Ambassador and a mentor at freeCodeCampReading. Ashnita is passionate about learning and thinks that writing and sharing ideas are great ways of learning. Besides coding, she loves the outdoors and nature.

Related Posts