Skip to content
JavaScript js strings 4 min read

Tagged Templates

A tagged template is a template literal placed immediately after a function. Instead of producing a string, the literal hands its raw pieces and interpolated values to that function, letting you intercept and reshape the result however you like. This small piece of syntax powers escaping helpers, internationalization libraries, and styling tools like styled-components — anywhere you want full control over how a string is assembled.

The syntax

Put a function name directly before a template literal (no parentheses, no comma). JavaScript calls that function — the tag — and passes it the deconstructed template.

function tag(strings, ...values) {
  console.log(strings);
  console.log(values);
}

const name = "Ada";
const age = 36;

tag`Hello ${name}, you are ${age} years old.`;

Output:

[ 'Hello ', ', you are ', ' years old.' ]
[ 'Ada', 36 ]

The tag receives the static text split around each ${}, and the interpolated values as separate arguments. The return value of the tag becomes the value of the whole expression — it does not even have to be a string.

The strings and values arguments

The first argument is an array of the literal string segments. The remaining arguments (gathered here with rest syntax into values) are the evaluated expressions, in order.

There is one guarantee worth memorizing: strings.length is always exactly values.length + 1. The text always brackets the values — there is a segment before the first ${} and after the last one, even if either is an empty string. That invariant makes it safe to interleave them in a loop.

function interleave(strings, ...values) {
  return strings.reduce((acc, str, i) => {
    const value = i < values.length ? values[i] : "";
    return acc + str + value;
  }, "");
}

const product = "Keyboard";
const price = 49;

console.log(interleave`The ${product} costs $${price}.`);

Output:

The Keyboard costs $49.

This interleave tag reproduces the default behavior of a plain template literal. Real tags do something more interesting in that loop.

Raw strings

The strings array carries a companion property, strings.raw, which holds the segments before escape sequences are processed. So \n stays as the two characters \ and n instead of a newline. This is exactly how String.raw — itself a built-in tag — works.

console.log(`Line1\nLine2`);
console.log(String.raw`Line1\nLine2`);

Output:

Line1
Line2
Line1\nLine2

String.raw is invaluable for Windows paths and regular-expression source strings, where you want backslashes left untouched: String.rawC:\Users\Ada“.

Use case: safe HTML escaping

A classic tag sanitizes only the interpolated values, never the static markup the developer wrote. This neutralizes injected <script> tags while leaving your own HTML intact.

const escapeHtml = (str) =>
  String(str)
    .replace(/&/g, "&amp;")
    .replace(/</g, "&lt;")
    .replace(/>/g, "&gt;")
    .replace(/"/g, "&quot;");

function safe(strings, ...values) {
  return strings.reduce(
    (acc, str, i) =>
      acc + str + (i < values.length ? escapeHtml(values[i]) : ""),
    ""
  );
}

const userInput = '<img src=x onerror="alert(1)">';
console.log(safe`<p>Comment: ${userInput}</p>`);

Output:

<p>Comment: &lt;img src=x onerror=&quot;alert(1)&quot;&gt;</p>

Use case: internationalization and styling

Tags shine wherever the structure of a string carries meaning beyond its characters.

Use caseWhat the tag does
EscapingSanitizes interpolated values (HTML, SQL, shell)
i18nUses the static segments as a lookup key, swaps in translations
styled-componentsTreats the literal as CSS and returns a styled component
Logging / SQLBuilds parameterized queries, keeping values separate from text

An i18n tag can hash the static parts into a stable key, fetch a translated template, and then re-inject the values in the right slots — meaning translators never touch your variables. Styling libraries such as styled-components use a tag to capture CSS text plus dynamic values (often functions of props) and compile it into a real component:

// Conceptual styled-components usage
const Button = styled.button`
  background: ${(props) => (props.primary ? "blue" : "gray")};
  padding: 8px 16px;
`;

The tag receives the CSS segments and the prop-reading functions, then generates a unique class name at render time.

Best practices

  • Use the strings/...values rest pattern and rely on the strings.length === values.length + 1 invariant rather than zipping by index manually.
  • Escape or transform only the interpolated values, never the trusted static segments authored by the developer.
  • Prefer String.raw (or strings.raw) when backslashes must survive — file paths, regex sources, LaTeX.
  • Return whatever type makes sense; a tag is free to produce objects, components, or numbers, not just strings.
  • Keep tag functions pure and fast — they may run on every render in UI frameworks.
  • Do not call the tag with parentheses; tag…“ and tag() are different operations.
Last updated June 1, 2026
Was this helpful?