Usage Guide

This comprehensive guide covers all aspects of using the Waltzing template language for building type-safe, compile-time HTML templates in Rust.

Quick Reference
  • File Extension: .wtz (e.g., template.html.wtz, component.wtz)
  • Purpose: Compile-time HTML template engine for Rust
  • Output: Type-safe Rust functions that generate HTML
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 @.

Expression Syntax

Pattern Usage Example
@variable Simple interpolation @user.name
@(expression) Complex expressions @(a + b * c), @(users.len() + 1)
@{ ... } Template expressions @{ <p>Hello</p> }
<@ component::func > Function Tag <@layout::main title="Home">
@safe(expr) Unescaped output @safe(html_content)
@@ Literal @ symbol user@@domain.com

When to Use Parentheses

Need parentheses:

  • Arithmetic operations: @(a + b * c)
  • Complex chained expressions: @(items.iter().filter().count())
  • Control flow expressions: @(if condition { value } else { other })
  • Logical operations: @(!user.can_edit)

No parentheses needed:

  • Simple function calls: @format("text", arg)
  • Member access: @user.name, @item.field
  • Method calls: @users.len(), @string.trim()
  • Array indexing: @items[0]

Imports and Uses

@use crate::models::*             // Import Rust types
@use chrono::DateTime
@use std::collections::HashMap

@import "layouts/main.wtz" as layout        // Import other templates
@import "components/header.wtz" as header

Function Definitions

Basic Syntax

@fn apply(
    title: String,
    posts: Vec,
    user: Option,
    current_time: DateTime
) {
    
}

Default Parameters

Functions can have default parameter values:

// Function with default parameters
@fn card(title: String, content: Content, class: String = "card") {
    

@title

@content
} // Usage with defaults <@card title="Welcome">

Hello world!

// Override the default <@card title="Welcome" class="special-card">

Hello world!

Default Parameters in Function Tags

When calling functions with default parameters via function tags, you can omit any parameters that have defaults. The function will use the default value automatically.

Control Flow

If/Else Statements

@if user.is_admin {
    
Admin Panel
} else if user.is_moderator {
Moderator Tools
} else {
User Content
} // If-let pattern matching @if let Some(profile) = user.profile {
Profile: @profile.bio
} else {
No profile available
}

For Loops

    @for item in items {
  • @item.name: $@item.price
  • }
// With enumeration @for (index, item) in items.iter().enumerate() {
  • @item.name
  • } // Labeled loops with break/continue @for outer_label: group in groups {
    @for item in group.items { @if item.should_break { @break :outer_label; } @item.name }
    }

    Pattern Matching

    @match user.status {
        UserStatus::Active => {
            Active
        }
        UserStatus::Pending => {
            Pending
        }
        UserStatus::Banned(reason) => {
            Banned: @reason
        }
        _ => {
            Unknown Status
        }
    }

    Function Tags

    Function tags provide HTML-like syntax for calling template functions, making component composition intuitive and readable.

    Basic Syntax

    // Self-closing function tag
    <@header::apply title="Page Title" />
    <@button::render text="Click me" disabled />
    
    // Function tag with content
    <@layout::apply title="My App">
        
    Page content goes here
    // Shorthand closing (closes nearest open tag) <@layout::apply title="Dashboard">

    Content here

    Attribute Types

    <@component::apply
        name="string literal"           // String literal (quoted)
        count=@@(items.len())           // Expression
        active=@user.is_active         // Simple expression
        title=@title                   // Variable value
        @variable                      // Shorthand for variable=@variable
        @@&reference                    // Shorthand for reference=@@&reference
        enabled                         // Boolean flag (true)
        class='single-quotes'           // Single-quoted string
    />
    Common Attribute Mistake

    DO NOT mix quotes with @:

    
    <@component name="@user.name" />
    
    
    <@component name=@user.name />
    <@component name="John Doe" />

    Content Parameter

    If a function's last parameter is of type waltzing::Content, it receives the tag body:

    // Function definition
    @fn layout(title: String, content: Content) {
        
            @title
            @content
        
    }
    
    // Function tag - body becomes content parameter
    <@layout title="My Page">
        
    This becomes the content parameter

    Default Parameter Values in Function Tags

    Function tags work seamlessly with default parameters, allowing you to omit attributes that have defaults:

    // Function with multiple defaults
    @fn button(
        text: String,
        variant: String = "primary",
        size: String = "medium",
        disabled: bool = false
    ) {
        
    }
    
    // All of these work:
    <@button text="Click me" />                        // Uses all defaults
    <@button text="Submit" variant="success" />        // Override one default
    <@button text="Cancel" variant="secondary" size="small" />  // Override multiple
    <@button text="Save" disabled />                   // Boolean flag syntax

    Underscore Parameter Convention

    Function tag parameters can omit leading underscores from function parameter names:

    // Function definition with underscore parameter
    @fn card(_title: String, _content: Content, _class: String = "card") {
        

    @_title

    @_content
    } // Function tag usage (omits underscores) <@card title="Welcome" class="special-card">

    Hello world!

    Special apply Shorthand

    If the function name is apply, it can be omitted:

    // These are equivalent:
    <@template::apply title="Page">Content
    <@template title="Page">Content

    HTML Attributes

    Conditional Attributes

    Dynamic Attribute Names

    // @attributeName - literal @@ prefix (for Alpine.js, Vue, etc.)
    

    Helper Functions

    format() - String Formatting

    Item @index
    @user.name

    @format("User {} has {} items", user.name, user.items.len())

    concat() - String Concatenation

    Button
    @page_title

    print() - Debug Output

    @print(user)           // Outputs debug representation
    @print(items.len())    // Outputs the length value

    Embedded Languages

    Use backtick syntax to switch language context for proper escaping and parsing.

    JSON/Alpine.js

    JavaScript

    CSS

    Structs and Enums

    Define custom types within templates with optional attributes:

    // Struct with attributes
    @struct[derive(Serialize), serde(rename_all = "camelCase")] ApiResponse {
        status: String,
        data[serde(skip_serializing_if = "Option::is_none")]: Option,
        error_code[serde(rename = "errorCode")]: Option,
    }
    
    // Enum with attributes
    @enum[derive(Serialize, Deserialize)] Status {
        Active,
        Inactive,
        Pending(String),
    }
    Default Derives

    By default, Waltzing adds Debug, Clone, and serde::Deserialize to all structs and enums. These can be disabled via Cargo features.

    Raw Content Blocks

    For content that should not be parsed by Waltzing:

    @@###
    This content is not parsed:
    @user.name stays as literal text
    
    @if condition { ... }
    ###@@

    Comments

    @@* Single-line Waltzing comment *@@
    
    @@**
        Multi-asterisk comments work too.
        Use matching counts: @@** **@@ or @@*** ***@@
    **@@
    
    
    Comments in Script/Style Tags

    Waltzing @* *@ comments work inside <script> and <style> tags and are stripped from the output.

    Template Organization

    your-project/
    ├── Cargo.toml
    ├── build.rs
    ├── src/
    │   └── main.rs
    └── templates/
        ├── layouts/         # Base templates
        │   └── main.wtz
        ├── components/      # Reusable components
        │   ├── header.wtz
        │   └── footer.wtz
        └── pages/           # Page templates
            ├── home.wtz
            └── about.wtz

    Common Patterns

    Form with Validation

    @fn form_field(name: String, value: String, errors: &ValidationErrors) {
        
    @if let Some(error) = errors.get(&name) { @error }
    }

    Alternating Row Styles

    @for (index, item) in items.iter().enumerate() {
        
    @item.name
    }

    Error Handling

    @match result {
        Ok(data) => {
            
    <@data_display::render @data />
    } Err(error) => {

    Error: @error

    } }

    Troubleshooting

    Template Not Found

    Check file paths are relative to templates directory and verify file extension is .wtz.

    Type Mismatch

    Ensure template parameters match expected types and check imported types are in scope with @use.

    Function Tag Parsing Errors

    Ensure function tags use <@module::function> syntax and closing tags match.

    Changes Not Reflected

    Run cargo clean and check template file permissions.