Security and Scripts
templ’s default posture: everything you interpolate is escaped for the context it lands in, and you opt out explicitly when you know better.
Auto-escaping
Expression output ({ expr } in text and in attribute values) is HTML-escaped automatically. There is no per-site “unsafe” mode to accidentally enable.
The only opt-out is templ.Raw, whose signature makes the intent visible at the call site (runtime.go):
func Raw[T ~string](html T, errs ...error) Component
Warning:
templ.Rawdisables escaping for its argument. Pass it markup you generated and trust; never raw user input.
Script templates
<script> blocks inside components are script templates. Placeholders written as {{ name }} are escaped for the JavaScript string context, so interpolated values cannot break out of the string and inject code:
templ player(clipID string) {
<script type="text/javascript">
function playClip() {
const id = "{{ clipID }}";
console.log(id);
}
</script>
<button onClick="playClip()">Play</button>
}
Script templates can also be rendered directly with @, like any other component.
templ.JSONScript
To hand server-side data to client-side JavaScript, use templ.JSONScript. It renders the value into a <script type="application/json"> tag (jsonscript.go):
templ chart(data []float64) {
@templ.JSONScript("chart-data", data)
<div id="chart"></div>
}
Client code reads the tag by its id and parses the JSON. The value is encoded server-side, so there is no string concatenation to get wrong.
const data = JSON.parse(document.getElementById("chart-data").textContent);
Further hardening
The security documentation covers three more topics worth reading once your app handles real users:
- Injection attacks - where untrusted input typically tries to get in
- Content Security Policy - defense in depth so injected script fails in the browser
- Code signing - verifying artifacts you distribute
Tip: Prefer script templates and
templ.JSONScriptovertempl.Rawfor anything data-shaped. Raw is for trusted markup, not for serializing values.