Embedded Languages

Waltzing supports embedded JavaScript, CSS, and JSON blocks with full template interpolation.

Matching Backticks Rule

The number of backticks in the opening tag must match the closing tag: @``` closes with ```@, and @```` closes with ````@.

JSON

Embed JSON data with template interpolation:

Basic Object

<div x-data=@```json {
    open: false,
    count: @initial_count,
    items: @items_json,
    userId: @user.id
} ```@>
    <button @click="open = !open">Toggle</button>
    <div x-show="open">Content here</div>
</div>

With Methods

<div x-data=@```json {
    isOpen: false,
    count: 0,

    toggle() {
        this.isOpen = !this.isOpen;
    },

    increment() {
        this.count++;
    },

    async fetchData() {
        const response = await fetch('/api/data');
        this.data = await response.json();
    }
} ```@>
    <button @click="toggle()">Toggle</button>
    <button @click="increment()">Count: <span x-text="count"></span></button>
</div>

With Getters and Setters

<div x-data=@```json {
    firstName: "@user.first_name",
    lastName: "@user.last_name",

    get fullName() {
        return this.firstName + ' ' + this.lastName;
    },

    set fullName(value) {
        const parts = value.split(' ');
        this.firstName = parts[0] || '';
        this.lastName = parts[1] || '';
    }
} ```@>
    <input x-model="fullName" />
    <p x-text="fullName"></p>
</div>

With Control Flow

<div x-data=@```json {
    userId: @user.id,
    @if user.is_admin {
        isAdmin: true,
        permissions: @admin_permissions,
    }
    @for field in default_fields {
        @field.name: @field.default_value,
    }
} ```@>
    ...
</div>

JSON Arrays

<script>
const items = @```json [
    @for item in items {
        { "id": @item.id, "name": "@item.name", "active": @item.active }
    }
] ```@;
</script>

JavaScript

Embed JavaScript with template values:

Configuration Objects

<script>
@```js
const config = {
    apiUrl: "@api_url",
    userId: @user.id,
    debug: @is_debug,
    features: @features_json
};

initApp(config);
```@
</script>

With Control Flow

<script>
@```js
const handlers = {
    @for handler in event_handlers {
        "@handler.event": @handler.callback,
    }
};

@if include_analytics {
    initAnalytics("@tracking_id");
}

@for script in inline_scripts {
    @script
}
```@
</script>

Event Handler Registration

<script>
@```js
document.addEventListener('DOMContentLoaded', () => {
    @for element in interactive_elements {
        document.getElementById("@element.id")
            .addEventListener("@element.event", (e) => {
                @element.handler
            });
    }
});
```@
</script>

CSS

Dynamic CSS with template interpolation:

Theme Variables

<style>
@```css
:root {
    --primary-color: @theme.primary;
    --secondary-color: @theme.secondary;
    --font-family: "@theme.font_family";
    --border-radius: @(theme.border_radius)px;
}

.theme-@theme.name {
    background-color: @theme.background;
    color: @theme.foreground;
}
```@
</style>

With Control Flow

<style>
@```css
@for breakpoint in breakpoints {
    @@media (min-width: @(breakpoint.width)px) {
        .container {
            max-width: @(breakpoint.max_width)px;
        }
    }
}

@if dark_mode_enabled {
    @@media (prefers-color-scheme: dark) {
        :root {
            --bg-color: #1a1a1a;
            --text-color: #ffffff;
        }
    }
}

@for color in brand_colors {
    .text-@color.name {
        color: @color.value;
    }
    .bg-@color.name {
        background-color: @color.value;
    }
}
```@
</style>

Inline Styles

<div style="@```style
    color: @text_color;
    background: @bg_color;
    padding: @(padding)px;
    @if has_border {
        border: 1px solid @border_color;
    }
```@">
    Content
</div>

Important Notes

Escaping @ in Embedded Blocks

Inside embedded blocks, use @@ to output a literal @ character:

@* In CSS - @@media becomes @media *@
@```css
@@media (min-width: 768px) { ... }
```@

@* @@click becomes @click in attributes *@
<button @click="toggle()">Toggle</button>

String vs Number Values

Use quotes for string values, no quotes for numbers/booleans:

@```json {
    name: "@user.name",       @* String - quoted *@
    count: @item_count,       @* Number - unquoted *@
    active: @is_active,       @* Boolean - unquoted *@
    items: @items_json        @* Pre-serialized JSON - unquoted *@
} ```@

Commas After Control Flow

Commas after @if, @for, and @match blocks are optional in JSON:

@```json {
    baseField: true
    @if extra {
        extraField: @extra_value
    }
    @for item in items {
        @item.key: @item.value
    }
    finalField: false
} ```@