Home Documentation Templates Examples Showcase GitHub
Theme

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.

No automatic escaping.

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:

ContextHelperEscaped characters
HTML text nodehtml_escape(value)& < >
Quoted HTML attributeattr_escape(value)& < > " '
URL componenturl_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>")
@// &lt;b&gt;&amp; hello&lt;/b&gt;

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("&amp;") produces &amp;amp;. Escape data once, at the point of output.

HTML attribute: attr_escape()

attr_escape("a"b&c")
@// a&quot;b&amp;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 &amp; or @ent('->') to &rarr;. 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().

See also

JSON data · Collection operations · Template language