Skip to content

Tagged Templates

This lesson explains Tagged Templates with clear examples, use cases, and best practices so you can use modern JavaScript confidently in real projects.

ES6+ Tagged Templates Overview

Tagged templates are an advanced form of template literals where a function processes the string before it is returned. Instead of writing `Hello`, you write tag`Hello`, and the tag function receives the string parts and interpolated values.

Tagged templates are useful for custom formatting, HTML escaping, internationalization, styled component libraries, SQL query builders, and any scenario where template output needs special processing.

Feature Description
Introduced In ES6 (ECMAScript 2015)
Syntax tagFunction`text ${value}`
Tag Function Receives String parts and interpolated values
Return Value Any value, often a processed string
Raw Strings strings.raw
Common Uses Escaping, i18n, styling, custom DSLs

Basic Tagged Template Example

function highlight(
  strings,
  ...values
) {
  return strings.reduce(
    (result, part, index) =>
      result +
      part +
      (values[index] !== undefined
        ? `[[${values[index]}]]`
        : ""),
    ""
  );
}

const name = "Alex";
const role = "Admin";

const message =
  highlight`User ${name} has role ${role}.`;

console.log(message);

The tag function receives the static string parts as an array and the interpolated values as separate arguments. It can transform the final output however you want.

How Tagged Templates Work

When JavaScript sees a tagged template literal, it first splits the template into string segments and expression values, then calls the tag function with those parts.

Step Description Example
Write Template Place a function name before backticks. tag`Hello ${name}`
Split Template Engine separates static and dynamic parts. ["Hello ", ""] and name
Call Tag Function Pass strings array and values. tag(strings, name)
Process Output Transform, escape, or format result. Custom logic inside tag
Return Value Tag function returns final result. String, object, or other value

Understand Tag Function Arguments

function inspect(
  strings,
  ...values
) {
  console.log("Strings:", strings);
  console.log("Values:", values);

  return strings.join("---");
}

const city = "Paris";

inspect`Welcome to ${city}!`;

For tag`Welcome to ${city}!`, the strings array contains "Welcome to " and "!", while values contains "Paris".

Use Raw Template Strings

function showRaw(strings) {
  console.log(strings[0]);
  console.log(strings.raw[0]);
}

showRaw`Line 1\nLine 2`;
const path =
  String.raw`C:\projects\app\src`;

console.log(path);

Tagged template string arrays include a raw property with unprocessed escape sequences. String.raw is a built-in tag for keeping backslashes unchanged.

Escape HTML with a Tag Function

function escapeHtml(value) {
  return String(value)
    .replace(/&/g, "&")
    .replace(/</g, "&lt;")
    .replace(/>/g, "&gt;")
    .replace(/"/g, "&quot;")
    .replace(/'/g, "&#39;");
}

function html(
  strings,
  ...values
) {
  return strings.reduce(
    (result, part, index) =>
      result +
      part +
      (values[index] !== undefined
        ? escapeHtml(values[index])
        : ""),
    ""
  );
}

const userInput = "<script>alert('xss')</script>";

const safeHtml =
  html`<p>Comment: ${userInput}</p>`;

console.log(safeHtml);

A common tagged template pattern is automatic escaping of dynamic values before inserting them into HTML or other sensitive output.

Styled Output Tag Example

function css(
  strings,
  ...values
) {
  return {
    className: "theme-card",
    styles: strings.reduce(
      (result, part, index) =>
        result +
        part +
        (values[index] ?? ""),
      ""
    )
  };
}

const primaryColor = "#2563eb";

const cardStyles =
  css`
    .card {
      color: ${primaryColor};
      padding: 16px;
    }
  `;

console.log(cardStyles);

Tagged templates can return objects instead of plain strings. This pattern is similar to how styled-component libraries process CSS templates in modern frontend development.

Internationalization Tag Example

const translations = {
  en: {
    greeting: "Hello, USER!"
  },
  fr: {
    greeting: "Bonjour, USER!"
  }
};

function i18n(lang) {
  return function (
    strings,
    ...values
  ) {
    const template =
      translations[lang].greeting;

    return template.replace(
      "USER",
      values[0]
    );
  };
}

const t = i18n("fr");
const message = t`${"Alex"}`;

console.log(message);

Tag functions can power translation systems by choosing the correct language template and inserting dynamic values safely.

Custom Formatting Tag

function currency(
  strings,
  ...values
) {
  const formattedValues =
    values.map((value) =>
      `${Number(value).toFixed(2)}`
    );

  return strings.reduce(
    (result, part, index) =>
      result +
      part +
      (formattedValues[index] ?? ""),
    ""
  );
}

const subtotal = 19.5;
const tax = 1.75;

const receipt =
  currency`Subtotal: ${subtotal} | Tax: ${tax}`;

console.log(receipt);

Tagged templates are useful when the same formatting rule should apply automatically to every interpolated value in a template.

Tagged Templates vs Regular Template Literals

Feature Tagged Template Regular Template Literal
Syntax tag`text` `text`
Processing Custom tag function runs first. Direct string interpolation only.
Return Type Any value. Always a string.
Best For Escaping, DSLs, styling, i18n. Simple dynamic strings.

Common Tag Function Patterns

Pattern Description Example Use
Reducer Pattern Combine strings and values with reduce(). HTML escaping, formatting.
Curried Tag Return a tag function from another function. Language or theme selection.
Object Return Return structured data instead of text. CSS-in-JS libraries.
Raw Access Use strings.raw for unescaped text. File paths and regex patterns.

Common Tagged Template Use Cases

  • Escaping HTML and preventing XSS in dynamic templates.
  • Building styled component and CSS-in-JS systems.
  • Creating translation and localization helpers.
  • Formatting numbers, dates, and currency automatically.
  • Constructing SQL or query DSLs with safer interpolation.
  • Generating markdown or custom markup languages.

Tagged Template Best Practices

  • Use tagged templates when every interpolated value needs the same processing.
  • Keep tag functions small, pure, and easy to test.
  • Escape or validate untrusted values inside the tag function.
  • Prefer regular template literals for simple one-off strings.
  • Document what your custom tag returns and expects.
  • Use curried tags when configuration such as language or theme is needed.
  • Handle missing values safely when combining strings and values.

Common Tagged Template Mistakes

  • Assuming tagged templates automatically sanitize HTML.
  • Forgetting that the tag function must rebuild the final string manually.
  • Not handling undefined interpolated values in reduce logic.
  • Using tagged templates for simple cases that only need normal templates.
  • Returning inconsistent value types from the same tag function.
  • Ignoring strings.raw when escape sequences must stay literal.
  • Building overly complex tag logic that belongs in normal functions.

Reusable Tag Helper

function joinTemplate(
  strings,
  ...values
) {
  return strings.reduce(
    (result, part, index) => {
      const value =
        values[index];

      return (
        result +
        part +
        (value === undefined ? "" : value)
      );
    },
    ""
  );
}

function bold(
  strings,
  ...values
) {
  return `**${joinTemplate(strings, ...values)}**`;
}

const product = "Keyboard";

console.log(
  bold`Featured product: ${product}`
);

Reusable helper functions make custom tags easier to maintain, especially when several tags share the same string-joining logic.

Key Takeaways

  • Tagged templates call a function before returning template literal output.
  • The tag function receives string parts and interpolated values separately.
  • They enable custom escaping, formatting, styling, and DSL behavior.
  • strings.raw and String.raw preserve unescaped text.
  • Use them when template processing should be automatic and reusable.

Pro Tip

Reach for tagged templates when the template itself needs a policy, such as escaping, translation, or formatting. If you only need to insert a variable, a regular template literal is enough.