Expressions

Output data from your Rust code into templates with type-safe expressions.

Simple Expressions

Use @ followed by an identifier to output a variable. Values are automatically HTML-escaped for security.

@user.name                 @* Field access *@
@items.len()               @* Method call *@
@items[0]                  @* Indexing *@
@user.profile.avatar_url   @* Nested access *@

Example:

@fn apply(user: User) {
    

Welcome, @user.name!

Email: @user.email

Member since: @user.created_at.format("%Y")

}

Complex Expressions

Use parentheses for inline expressions with operators:

@(a + b)                   @* Arithmetic *@
@(count * 2 + 1)           @* Multi-operator *@
@(value as f64)            @* Type cast *@
@(if cond { a } else { b }) @* Inline if *@

Example:

@fn apply(items: Vec, tax_rate: f64) {
    

Total items: @items.len()

Page @(current_page + 1) of @total_pages

Tax: $@(subtotal * tax_rate)

}

Variable Bindings

Use @let to create local variables within templates.

Greedy Parsing

Operators work directly in @let statements — no parentheses needed. The parser uses greedy parsing to consume the full expression.

@let name = user.name
@let total = a + b                @* Operators work directly *@
@let valid = x > 0 && y < 10     @* Boolean operators too *@
@let cast = value as i32          @* Type casts too *@
@let x = a + b;                   @* Optional semicolon terminator *@

Practical example:

@fn apply(items: Vec, discount: f64) {
    @let subtotal = items.iter().map(|i| i.price).sum::()
    @let discount_amount = subtotal * discount
    @let total = subtotal - discount_amount

    

Subtotal: $@subtotal

Discount: -$@discount_amount

Total: $@total

}

Safe (Unescaped) Output

By default, all output is HTML-escaped. Use @safe() for trusted HTML content:

@safe(html_content)                    @* Output without escaping *@
@safe(markdown_html, "

fallback

") @* With fallback value *@
Security Warning

Only use @safe() with content you trust. Never use it with user input.

Example:

@fn apply(article: Article) {
    

@article.title

@* Title is escaped - safe from XSS *@
@safe(article.rendered_html)
@* rendered_html is trusted, pre-sanitized content *@ }

Escaping the @ Symbol

Use @@ to output a literal @ symbol:

@@                      @* Outputs: @ *@
email@@example.com      @* Outputs: email@example.com *@
Raw Blocks

Inside @#...#@ raw blocks (any matching number of #), content is output verbatim - no escaping needed. The @@ escape is only needed outside raw blocks to output a literal @.

Macro-like Constructs

These compile-time transforms generate Rust macros. Both @keyword() and keyword() syntax work:

@matches() - Pattern Matching

Compiles to Rust's matches!() macro for inline pattern matching:

@* Simple enum variant matching *@
@if matches(active_tab, ViewProfileTab::ChangePassword) {
    
Change Password Form
} @* With or-patterns *@ @if matches(status, Status::Active | Status::Pending) { Processing... } @* With guards *@ @if matches(value, Some(x) if x > 5) { Value is greater than 5 }

@format() - String Formatting

Compiles to Rust's format!() macro:

@format("{} items found", count)
format("{:.2}", price)              @* Also works without @ *@
Profile

@print() - Concatenation

Concatenates arguments using format!("{}{}", ...):

@print(a, b, c)                     @* -> format!("{}{}{}", a, b, c) *@
print("Hello, ", name, "!")         @* Also works without @ *@
Expression Bodies

In expression bodies (after = {#{), use format() and print() without the @ prefix:

@fn time_json(items: &Vec): String = {
    format("[{}]", items.iter().map(|i|
        format("{{name:'{}'}}", i.name)
    ).collect::>().join(","))
}

Expressions in Attributes

Expressions work seamlessly in HTML attributes:

@label
@image.alt

Dynamic classes example:

@fn apply(item: Item) {
    
}

Expression Summary

Syntax Description Example
@var Simple variable (escaped) @user.name
@obj.field Field access @user.profile.bio
@obj.method() Method call @items.len()
@(expr) Complex expression @(a + b)
@safe(html) Unescaped output @safe(rendered_md)
@let x = val Variable binding @let total = (a + b)
@matches(expr, pat) Pattern matching @if matches(x, Some(_))
@format(fmt, args) String formatting @@format("{}", val)
@print(a, b, c) Concatenation @print("Hi ", name)
@@ Literal @ symbol email@@example.com