← CodeClarityLab Home
Browse by Category
+ added · updated 7d
← Back to glossary

Tagged Template Literals

javascript ES2015 Intermediate
debt(d5/e3/b3/t7)
d5 Detectability Operational debt — how invisible misuse is to your safety net

Closest to 'specialist tool catches it' (d5). The detection_hints indicate eslint and semgrep can catch code patterns like unsanitised template interpolation or missing tagged templates for SQL queries, but these require rule configuration and are not caught by default linters on all misuses—only on specific anti-patterns.

e3 Effort Remediation debt — work required to fix once spotted

Closest to 'simple parameterised fix' (e3). The quick_fix describes switching to a tagged template library (like htm), which is a localised refactor within a component: replace template literal syntax with a tag function call and ensure the tag function handles escaping. This doesn't span multiple files or require architectural change.

b3 Burden Structural debt — long-term weight of choosing wrong

Closest to 'localised tax' (b3). Tagged templates are a pattern choice that applies to contexts where HTML/SQL interpolation occurs (web, cli per applies_to), but the burden falls on the component where the tag is used and developers who maintain that interpolation. It doesn't reshape the entire codebase or impose a system-wide architectural load—other components can use plain functions or other patterns.

t7 Trap Cognitive debt — how counter-intuitive correct behaviour is

Closest to 'serious trap' (t7). The misconception field explicitly states that developers often believe tagged templates are 'just syntax sugar' when they actually transform output entirely and receive raw values separately from strings. This contradicts superficial understanding and is further compounded by common_mistakes like forgetting the strings array has one more element than values, and the non-obvious requirement to manually sanitise values in the tag function—developers may assume the tag magic handles escaping automatically.

About DEBT scoring →

Also Known As

tagged templates template tag tag function gql tag

TL;DR

A function prefix on a template literal — the tag function receives the string parts and interpolated values separately, enabling safe SQL, HTML, CSS, and i18n string construction.

Explanation

A tagged template calls a function with the literal string parts (as an array) and the interpolated values as separate arguments. The tag function can process, escape, or transform both. Common uses: SQL query builders (prevent injection by separating literals from values), HTML escaping, CSS-in-JS, GraphQL queries (gql tag), and i18n formatting. The template tag is called at parse time if the values are all known — otherwise at runtime with the actual values.

Common Misconception

Tagged templates are just syntax sugar for template literals — the tag function transforms the output entirely; the result does not have to be a string at all.

Why It Matters

Tagged templates are the cleanest way to build SQL queries or HTML in JavaScript without injection risks — the tag function receives raw values separately and can escape them correctly.

Common Mistakes

  • Not escaping HTML values in a custom html tag — the benefit is lost if values aren't sanitised.
  • Forgetting that the strings array has one more element than the values array.
  • Using tagged templates where a plain function would be clearer — tags are best for DSLs.
  • Not handling the raw strings array for regex/string-escape use cases.

Code Examples

✗ Vulnerable
// SQL injection risk — string concatenation:
const query = `SELECT * FROM users WHERE id = ${userId}`;
// userId = '1 OR 1=1 --' → returns all users

// XSS risk — unescaped interpolation:
const html = `<div>${userInput}</div>`;
✓ Fixed
// Safe SQL via tagged template:
function sql(strings, ...values) {
    return {
        text: strings.reduce((q, s, i) => q + s + (i < values.length ? `$${i+1}` : ''), ''),
        values,  // Driver handles parameterised query
    };
}
const query = sql`SELECT * FROM users WHERE id = ${userId}`;
// query = { text: 'SELECT * FROM users WHERE id = $1', values: [userId] }

// Safe HTML escaping:
const escape = s => String(s).replace(/&/g,'&amp;').replace(/</g,'&lt;');
const html = (strings, ...vals) => strings.reduce((r,s,i) => r+s+(vals[i]!=null?escape(vals[i]):''),'');
const output = html`<div>${userInput}</div>`;

Added 16 Mar 2026
Edited 22 Mar 2026
Views 33
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings T 0 pings F 0 pings S 0 pings S 1 ping M 0 pings T 1 ping W 0 pings T 0 pings F 1 ping S 0 pings S 0 pings M 0 pings T 1 ping W 0 pings T 1 ping F 0 pings S 1 ping S 1 ping M 0 pings T 0 pings W 0 pings T 1 ping F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 0 pings F
No pings yet today
No pings yesterday
Perplexity 10 Google 7 Unknown AI 2 Ahrefs 2 SEMrush 2 Majestic 1 Amazonbot 1 Qwen 1 ChatGPT 1
crawler 24 crawler_json 3
DEV INTEL Tools & Severity
🟡 Medium ⚙ Fix effort: Medium
⚡ Quick Fix
Use tagged templates to safely interpolate user content into HTML (like htm library) or SQL — the tag function receives raw strings and values separately, letting you sanitise each value before inserting
📦 Applies To
javascript ES2015 web cli
🔗 Prerequisites
🔍 Detection Hints
Template literal with user input directly in innerHTML; no tagged template for SQL queries; XSS from unsanitised template interpolation
Auto-detectable: ✓ Yes eslint semgrep
⚠ Related Problems
🤖 AI Agent
Confidence: Medium False Positives: Medium ✗ Manual fix Fix: Medium Context: Function Tests: Update
CWE-79

✓ schema.org compliant