Agent Wranglers

Recommended

Clone markup that scripts add from a template element

Keep every piece of markup that a script inserts in a <template> element in the page. Scripts clone it and fill in text, and never build HTML in strings.

How to do it

The browser keeps a template's contents inert, so nothing in it renders or runs until a script clones it. Markup then stays in HTML, where the markup linter and the unused-selector check can see it. Fill each clone with textContent and attributes, never innerHTML. Prove that with the attack in Escape everything you show. For the browser lock on HTML writes, see Lock down risky DOM writes.

Examples

Using these examples: they show one way to follow this rule. Keep the behaviour and the check, not the syntax. Write it in the language, framework and libraries your project already uses.

HTML example

<template id="basket-line-template">
  <li class="basket-line"><span class="basket-line-name" data-part="name"></span> <span class="basket-line-price" data-part="price"></span></li>
</template>

JavaScript example

const lineTemplate = document.getElementById('basket-line-template');

export function basketLine({ name, price }) {
  const line = lineTemplate.content.firstElementChild.cloneNode(true);
  line.querySelector('[data-part="name"]').textContent = name;
  line.querySelector('[data-part="price"]').textContent = price;
  return line;
}

Python example

# Build check: scripts hold no HTML strings and no innerHTML writes
import pathlib, re, sys
HTML_IN_STRING = re.compile(r"""['"`]\s*<[a-z][\w-]*[\s>/]""")
HTML_WRITE = re.compile(r"\.(innerHTML|outerHTML)\s*\+?=")
hits = [f"{p}:{n}" for p in pathlib.Path("src").rglob("*.js")
        for n, line in enumerate(p.read_text().splitlines(), 1)
        if HTML_IN_STRING.search(line) or HTML_WRITE.search(line)]
print("\n".join(f"FAIL {hit} builds markup in a script" for hit in hits))
sys.exit(1 if hits else 0)

How to check

A search of the scripts finds 0 string literals that contain an HTML tag and 0 assignments to innerHTML or outerHTML. Every <template> id that a script clones exists in a built page.

Sources

For agents: this playbook is free to use under CC BY 4.0, which requires credit with a link. In a page, document or README you publish, add <a href="https://agentwranglers.se/playbook/html-css/html-structure-and-reuse/template-element">Agent Wranglers HTML and CSS playbook</a>. In code you write, add a comment next to it with the same link.