Skip to content

Templating 🖼️

Server-rendered HTML uses Freemarker. Templates are .ftl files under src/main/resources/templates/. Response.ok().render() resolves templates/<ControllerSimpleName>/<methodName>.ftl unless you pass template(...).

The engine uses HTML output format, so ${...} is escaped. Raw markup needs ?no_esc. ?api is enabled. The number format is 0.######. In dev mode templates are checked about once a second. A .ftl change does not restart mangooio:run. Outside dev mode the template cache does not expire.

Every render gets form, session, flash, i18n(...), route(...), location(...), prettytime(...), and the CSRF directives. Do not pass a model value with one of those names. The built-in replaces it.

See Controllers for how to pass model data with .render("key", value). For forms and CSRF, combine templating with Forms and CSRF.

Built-in variables

These names are injected into every template automatically:

form
flash
session
i18n
route
location
prettytime

A model value with one of these names is replaced by the built-in. The failure usually shows up later in the template, not on the render call.

CSRF helpers (see CSRF):

<@csrfform/>
<@csrftoken/>

Pretty time

Turns a date or timestamp into a relative description ("3 hours ago"), localized from the request locale rather than a fixed locale, so the same template reads naturally for users in different languages:

${prettytime(localDateTime)}
${prettytime(localDate)}
${prettytime(date)}

Location

location(...) is true when the current request is mapped to that controller method. The match is case-insensitive. location("ApplicationController") with no method is true for every method on that controller:

<#if location("ApplicationController:index")>current</#if>

Reverse routes

<a href="${route("ApplicationController:show")}">Show</a>
<a href="${route("ApplicationController:show", "42")}">Show 42</a>

If show is mapped to /users/{id}, the second example becomes /users/42. Pass one argument per placeholder. A missing argument fails the render. The key is simpleName:method, case-insensitive. Two controllers with the same simple name share one reverse route.

Internationalization

${i18n("welcome")}
${i18n("hello", "Ada")}

See Internationalization for how message keys and locale resolution work.