Untagged Template Literals... The Upgrade You Didn’t Know You Needed!

February 13, 2025 | 7 Minute Read

Have you ever felt like some of the dynamic expressions in your Angular component templates are a tangled mess? What if I told you we now have a cleaner, more modern way to handle dynamic classes, styles, and even complex interpolations, without the headache?

In this tutorial, I’ll show you how Angular 19.2-next.0 introduces untagged template literals that make your templates cleaner, easier to maintain, and even unlock some tricks you couldn’t do before.

Simplify Your Class Bindings

For this example, we’ll be using a basic message component.

This component can be in three different states: an “error” state, a “success” state, or a “warning” state:

Example of a simple message component in Angular that uses traditional string concatenation for dynamic property binding before switching to newly introduced template literals

In the template, we’re currently using traditional string concatenation, with plus symbols, and a ternary operator, to bind the “message-error” or “message-success” class.

<div [class]="'message-' + (isError() ? 'error' : 'success')">
    ...
</div>

That’s how we used to do it, but not anymore.

Now, we can replace the old-school concatenation with template/string literals.

Just wrap the expression in backticks and replace the plus signs and parentheses with the embedded expression syntax using the dollar sign and curly braces. That’s it!:

<div [class]="`message-${isError() ? 'error' : 'success'}`">
    ...
</div>

This does the exact same thing, just in a slightly cleaner, more readable way.

This is pretty cool because it can really simplify expressions in templates.

Dynamic Styles, Now Cleaner Than Ever!

Now, let’s apply this concept to some existing dynamic styles.

Here, we’re setting three different custom properties using traditional concatenation:

<div [style]="
    '--error:' + errorColor + 
    '; --success:' + successColor + 
    '; --warning:' + warningColor + ';'">
    ...
</div>

But since we now have template literals, we can clean this up:

<div [style]="`
    --error: ${errorColor}; 
    --success: ${successColor}; 
    --warning: ${warningColor};`">
    ...
</div>

With just one quick change, the expression becomes simpler and easier to maintain.

And this too is equivalent to what we had before, just in a slightly cleaner, more readable fashion.

Easier Image Paths & File Names

Next up, we can improve dynamic image paths and file names too.

Here’s an SVG icon that updates based on the message state using attribute binding:

<svg aria-hidden="true" viewBox="0 0 24 24">
    <use [attr.href]="'/assets/icons.svg#' + iconName()"></use>
</svg>

It does this by adding a dynamic SVG fragment name that matches the identifier from the SVG file itself:

<svg xmlns="http://www.w3.org/2000/svg">
  <symbol id="success">...</symbol>
  <symbol id="error">...</symbol>
  <symbol id="warning">...</symbol>
</svg>

Right now, the fragment name is built using string concatenation, but we can replace that with a template literal instead:

<svg aria-hidden="true" viewBox="0 0 24 24">
    <use [attr.href]="`/assets/icons.svg#${iconName()}`"></use>
</svg>

There, that’s better.

And after saving, everything should still work perfectly.

Simplify Clunky Interpolations with Multiple Expressions

Template literals also shine when combining multiple interpolations.

Take this message:

<p>Message type: [{{ messageType() }}] - {{ message() }}</p>

It’s built with a mix of static text, a string interpolated “messageType” input, more text, and then the string interpolated “message” input itself.

This isn’t horrible as it stands, but now we can turn this into one single template literal, keeping everything in a single, readable expression:

<p>{{ `Message type: [${messageType()}] - ${message()}` }}</p>

So, that’s just another way this can be done.

Now, would I use this approach in this case?

Maybe not. But it’s nice to have the option!

Unlocking New Possibilities with Pipes

Now here’s a case where template literals actually unlock new possibilities.

Here we have some static text again followed by the date using a dynamic “date” property and the built-in Angular date pipe to format it appropriately:

<time>today is: {{ today | date:'fullDate' }}</time>

Now, we want to convert this entire expression to uppercase characters.

Well, Angular has a built-in pipe for this too, the Uppercase pipe.

Unfortunately, we have no way to apply this to the current expression as is, because it’s partially static text and partially a formatted date with the date pipe.

But, by switching this all over to a single expression using a template literal instead, we can actually add the uppercase pipe now:

<time>{{ `today is ${today | date:'fullDate'}` | uppercase }}</time>

This is pretty cool because before, you couldn’t do this in the template.

You’d have to format it programmatically.

Now, it’s just one line, all within the template.

Conclusion – Cleaner, Simpler, Better Templates!

Just like that, our template expressions are cleaner with template literals!

No more clunky string concatenations, just simple, modern syntax that gets the job done.

So, what do you think?

Will this make your Angular templates cleaner?

If you found this helpful, don’t forget to subscribe, and check out my other Angular tutorials for more tips and tricks!

Additional Resources

Want to See It in Action?

Check out the demo code showcasing these techniques in the StackBlitz project below. If you have any questions or thoughts, don’t hesitate to leave a comment.