Output safety · Core reference
Escaping & encoding.
Dynamic values that end up in HTML must be escaped for the context they appear in. Nift keeps interpolation raw by default and provides three explicit helpers — html_escape(), attr_escape() and url_encode() — one per output context.
Ordinary $[...] interpolation is not HTML-escaped automatically. That is a deliberate compatibility property: a template renders exactly the value it binds. When a value may contain markup-significant characters, apply the explicit helper that matches its destination context.
Three output contexts
A value can be emitted into three different places, each with its own rules:
| Context | Helper | Escaped characters |
|---|---|---|
| HTML text node | html_escape(value) | & < > |
| Quoted HTML attribute | attr_escape(value) | & < > " ' |
| URL component | url_encode(value) | RFC 3986 percent-encoding of everything except unreserved characters |
Quotes do not need escaping in text nodes, so html_escape() leaves them alone; attr_escape() escapes both quote styles so the result is safe inside either "..." or '...' attributes. Documentation examples use quoted attributes.
HTML text: html_escape()
html_escape("<b>& hello</b>")
@// <b>& hello</b> Use it for text that will appear between tags:
<p>$[html_escape(post.title)]</p> Because the function escapes every &, input that already contains an entity is re-escaped: html_escape("&") produces &amp;. Escape data once, at the point of output.
HTML attribute: attr_escape()
attr_escape("a"b&c")
@// a"b&c <input value="$[attr_escape(form.value)]">
<div data-value="$[attr_escape(record.status)]"></div> Always write the attribute with quotes around the interpolation.
URL component: url_encode()
url_encode("a b/c?d=e&f")
@// a%20b%2Fc%3Fd%3De%26f url_encode() percent-encodes a single URL component (a path segment or a query value). It is RFC 3986 encoding, not form encoding: a space becomes %20, never +. It does not sanitize a complete URL — pass one dynamic component at a time.
<a href="/search?q=$[url_encode(query)]">Search</a>
<a href="/products/$[url_encode(product.slug)]">$[html_escape(product.name)]</a> Composing contexts
The contexts compose. A dynamic search link whose query value may contain &, spaces, quotes or Unicode needs two steps: percent-encode the value into a URL component, build the URL, then attribute-escape the final attribute value.
$[encoded := url_encode(query)]
$[href := "/search?q=" + encoded] <a href="$[attr_escape(href)]">Search</a> Neither html_escape() alone nor url_encode() alone safely constructs a URL embedded in HTML: html_escape() does not percent-encode URL-reserved characters, and url_encode() does not escape attribute quotes.
Relationship to @ent
@ent(name) (documented on the Template language page) maps a specific symbol or token to its named HTML entity — for example @ent('&') to & or @ent('->') to →. It is a fixed symbol-to-entity lookup used for markup, not a general escaping operation. When you need to escape arbitrary data, use html_escape(), attr_escape() or url_encode().