Tagged Template Literals

Med

Tagged template literals let you process template strings with a function. The tag function receives an array of string segments and the interpolated values as separate arguments, giving you full control over how the template is assembled. This pattern powers styled-components, GraphQL queries (gql), and HTML sanitization.

Interactive Visualization

Tagged Templates

A tagged template literal is called
highlight`Hello ${name}!`

Key Points

  • A tag function receives (strings[], ...values) — strings are the static parts, values are the expressions
  • The strings array always has one more element than the values array
  • strings.raw gives unprocessed escape sequences (backslashes preserved)
  • String.raw is the built-in tag that returns raw strings without processing escapes
  • Tags enable DSLs like html`<p>${text}</p>`, css`color: ${c}`, sql`SELECT * FROM ${table}`
  • The tag function can return anything — not just strings

Code Examples

Tag Function Basics

function tag(strings, ...values) {
  console.log(strings) // ['Hello ', '! You are ', '.']
  console.log(values)  // ['Alice', 30]
  return strings.reduce((result, str, i) => {
    return result + str + (values[i] !== undefined ? values[i] : '')
  }, '')
}

const name = 'Alice'
const age = 30
const result = tag`Hello ${name}! You are ${age}.`
console.log(result) // 'Hello Alice! You are 30.'

The tag function receives static string segments and dynamic values separately.

HTML Sanitization Tag

function safeHtml(strings, ...values) {
  const escape = (str) =>
    String(str)
      .replace(/&/g, '&amp;')
      .replace(/</g, '&lt;')
      .replace(/>/g, '&gt;')

  return strings.reduce((result, str, i) => {
    const val = i < values.length ? escape(values[i]) : ''
    return result + str + val
  }, '')
}

const userInput = '<script>alert("xss")</script>'
const html = safeHtml`<div>${userInput}</div>`
// '<div>&lt;script&gt;alert("xss")&lt;/script&gt;</div>'

The tag function escapes interpolated values to prevent XSS attacks. Static string parts are trusted.

String.raw

const normal = `Line1\nLine2`
console.log(normal) // Line1 (newline) Line2

const raw = String.raw`Line1\nLine2`
console.log(raw) // 'Line1\nLine2' (literal)

// Useful for regex and file paths
const path = String.raw`C:\Users\alice\docs`
console.log(path) // 'C:\Users\alice\docs'

String.raw returns the raw string without processing escape sequences.

SQL Tag for Parameterized Queries

function sql(strings, ...values) {
  const params = []
  const query = strings.reduce((result, str, i) => {
    if (i < values.length) {
      params.push(values[i])
      return result + str + '$' + params.length
    }
    return result + str
  }, '')
  return { query, params }
}

const table = 'users'
const minAge = 18
const result = sql`SELECT * FROM ${table} WHERE age >= ${minAge}`
console.log(result.query)  // 'SELECT * FROM $1 WHERE age >= $2'
console.log(result.params) // ['users', 18]

Tags can return any value. This SQL tag creates parameterized queries, preventing SQL injection.

Common Mistakes

  • Forgetting that strings always has one more element than values
  • Assuming the tag function must return a string — it can return anything
  • Confusing template literal expressions with tag function arguments

Interview Tips

  • Explain the signature: tag(strings, ...values) where strings.length === values.length + 1
  • Mention real-world uses: styled-components, GraphQL gql, Lit html
  • Demonstrate the sanitization pattern for security awareness
  • String.raw is the only built-in tag function in the language

Related Concepts