Skip to content
Kona

Rendering & data

Crema evaluates expressions against the data map you pass to view / render (and nested maps, lists, and bean-style getters). This page covers how values become HTML — escaped or raw — and the helpers that turn data into JSON, URLs, and translation strings. For making views from controllers, see the View helper.

Every render starts with a Map<String, Any?> (Kotlin) or Map<String, ?> (Java). Keys become top-level names in the template:

view(
"posts.show",
mapOf(
"title" to "Hello",
"post" to post,
"tags" to listOf("kona", "jvm"),
),
).render()
<h1>{{ title }}</h1>
<p>{{ post.body }}</p>

Nested paths use dots: post.body walks map keys or zero-arg getters (getBody(), isActive(), or a method/field named body).

View.with(key, value) / with(map) merges more keys before render(). Child contexts (includes, loops, components) inherit parent data and may overlay loop variables or slots.

{{ expr }} prints the value as text with HTML escaping for &, <, >, ", and ':

<p>Hello {{ name }}</p>
{{-- name = "<script>" → Hello &lt;script&gt; --}}

Empty or missing values render as an empty string — not the literal null.

{!! expr !!} prints without escaping. Use only for trusted markup you built yourself (or already sanitized):

<div class="prose">{!! html !!}</div>

Unclosed {!! / {{ sequences are errors at render time.

Syntax Result
@@ A single @ in the output (useful when documenting directives)
{{-- … --}} Comment — stripped before any other processing
{{-- Never appears in HTML --}}
<code>@@extends</code>

Echoes and most directive arguments accept a small expression language:

Kind Examples
Literals true, false, null / nil, 42, 3.5, 'string', "string"
Comparisons ==, !=, <, >, <=, >= (numbers compare numerically; otherwise stringified)
Logic and, or, not …, !…
Helpers isset(name), empty(name)
Paths user.name, errors.email
@if(count > 0 and ready)
Ready
@endif
{{ isset(name) }}
{{ empty(items) }}
{{ not ok }}
{{ a == 1 or b == 2 }}

isset(path) is true when the resolved value is non-null. empty(path) is true when the value is not truthy (see truthiness).

There is no arbitrary code execution in templates — only this expression subset and property access.

@json($expr) encodes a value as JSON (Jackson). Useful inside <script> or data attributes:

<script>
window.bootstrap = @json($user);
</script>
crema.render(
"page",
mapOf("user" to mapOf("name" to "Ada", "id" to 1)),
)
// → window.bootstrap = {"name":"Ada","id":1};

@lang('key') resolves a translation string. Crema prefers a lang map in the view data when present; otherwise it calls Lang.get from kona-support.

@lang('messages.welcome')
@lang('messages.hello', replace)

The optional second argument is an expression that evaluates to a Map of replacements. Placeholders in the string use :name form (Hi :name + name → Ada → Hi Ada).

crema.render(
"greet",
mapOf(
"replace" to mapOf("name" to "Ada"),
// or override a single key:
// "lang" to mapOf("messages.hello" to "Hi :name"),
),
)

Register SupportServiceProvider (or call Lang.setTranslator) before rendering when you rely on the global translator.

@asset('css/app.css') builds a public URL. With no base in the data map it emits /css/app.css. Pass asset_url or assetUrl to prefix a CDN:

<link rel="stylesheet" href="@asset('css/app.css')" />

Leading slashes on the path argument are trimmed before joining.

@vite('resources/js/app.js') emits a script (or link) tag pointing at /build/.... Lists are supported:

@vite('resources/js/app.js')
@vite(['resources/js/app.js', 'resources/css/app.css'])

.css entries become <link rel="stylesheet">; everything else becomes <script type="module">. This helper is intentionally thin — it does not read a Vite manifest. For hot-reload and manifest resolution, see Vite / asset bundling and Inertia.

Situation Behavior
Missing key in {{ name }} Empty string
null / nil literal Empty string when echoed
Nested null (user.name when user is null) Empty string
Unclosed {{ or {!! Render throws
Map vs bean Maps use key lookup; other objects use getters / zero-arg methods / public fields