Advanced SSR FULL

Server-side generation, computed properties, form handling, and nested data structures. For basic SSR setup, see Server-Side Rendering (SSR). For lifecycle, architecture, and troubleshooting, see SSR Internals.

Sandbox Examples: SSR examples run in isolated environments due to server-rendering requirements. Each example is a self-contained demonstration.

Server-Side Generation

To use SSR, your server needs to produce HTML that WildflowerJS can hydrate. The key rules are:

  • Add data-ssr="true" to the component root element
  • Include data-bind attributes on elements that map to state properties
  • Include a <template> inside each data-list for future client-side additions
  • Use data-type for non-string values (number, boolean, json)

Node.js / Express

function renderUserDashboard(userData) {
    return `
        <div data-component="user-dashboard" data-ssr="true">
            <h2 data-bind="name">${escapeHtml(userData.name)}</h2>
            <p data-bind="email">${escapeHtml(userData.email)}</p>

            <div data-list="notifications">
                <template>
                    <div class="notification">
                        <span data-bind="message"></span>
                        <time data-bind="timestamp"></time>
                    </div>
                </template>

                ${userData.notifications.map(notif => `
                    <div class="notification">
                        <span data-bind="message">${escapeHtml(notif.message)}</span>
                        <time data-bind="timestamp">${escapeHtml(notif.timestamp)}</time>
                    </div>
                `).join('')}
            </div>
        </div>
    `;
}

// Express route
app.get('/dashboard', async (req, res) => {
    const userData = await getUserData(req.user.id);
    const html = renderUserDashboard(userData);
    res.send(pageTemplate(html));
});

PHP

<?php
function renderProductCatalog($products) {
    $items = '';
    foreach ($products as $p) {
        $name = htmlspecialchars($p['name']);
        $price = number_format($p['price'], 2);
        $items .= "<div class=\"product\">
            <strong data-bind=\"name\">{$name}</strong>
            <span data-bind=\"price\" data-type=\"number\">\${$price}</span>
        </div>";
    }

    return '<div data-component="product-catalog" data-ssr="true">
        <h1 data-bind="title">Product Catalog</h1>
        <div data-list="products">
            <template>
                <div class="product">
                    <strong data-bind="name"></strong>
                    <span data-bind="price" data-type="number"></span>
                </div>
            </template>' . $items . '
        </div>
    </div>';
}
?>

Python / Django

# Django template (todos/templates/todo_list.html)
<div data-component="todo-list" data-ssr="true">
    <h2>My Todos</h2>
    <div data-list="todos">
        <template>
            <div class="todo-item">
                <input type="checkbox" data-model="completed" data-type="boolean">
                <span data-bind="text"></span>
            </div>
        </template>

        {% for todo in todos %}
        <div class="todo-item">
            <input type="checkbox"
                   data-model="completed"
                   data-type="boolean"
                   {% if todo.completed %}checked{% endif %}>
            <span data-bind="text">{{ todo.text }}</span>
        </div>
        {% endfor %}
    </div>
</div>
Important: Always HTML-escape user content on the server. The template syntax shown above (Django {{ }}, PHP htmlspecialchars()) is your server-side templating. WildflowerJS itself does not use template syntax.

Computed Properties with SSR

The server can pre-render computed values so they appear instantly. When the client activates, computed properties take over and recalculate reactively.

SSR Example Order Summary with Computed Totals Open Full Example ↗
Server-Rendered Computed Values:
<div data-component="order-summary" data-ssr="true">
    <!-- Server pre-renders the computed totals -->
    <p>Subtotal: $<span data-bind="subtotal">223.94</span></p>
    <p>Tax: $<span data-bind="tax">22.39</span></p>
    <p>Total: $<span data-bind="total">246.33</span></p>
</div>
How it works: The server calculates and renders the totals. On hydration, computed properties are recalculated by the client. Adjust quantities to see reactivity take over.
wildflower.component('order-summary', {
    state: {
        items: [
            { name: 'Wireless Headphones', price: 79.99, quantity: 2 },
            { name: 'USB-C Cable', price: 12.99, quantity: 3 },
            { name: 'Phone Case', price: 24.99, quantity: 1 }
        ],
        taxRate: 0.10
    },

    computed: {
        subtotal() {
            return this.items.reduce((sum, item) =>
                sum + (item.price * item.quantity), 0
            ).toFixed(2);
        },

        tax() {
            return (parseFloat(this.subtotal) * this.taxRate).toFixed(2);
        },

        total() {
            return (parseFloat(this.subtotal) + parseFloat(this.tax)).toFixed(2);
        }
    }
});

Form Handling

SSR forms require data-model (not data-bind) for inputs. Checkboxes need data-type="boolean" so the framework parses checked state correctly.

SSR Example Todo List with SSR Form State Open Full Example ↗
Server-Rendered Todo with Form State:
<div data-list="todos">
    <template>
        <div class="todo-item">
            <input type="checkbox" data-model="completed" data-type="boolean">
            <span data-bind="text"></span>
        </div>
    </template>

    <!-- Server-rendered with checkbox state -->
    <div class="todo-item">
        <input type="checkbox" data-model="completed"
               data-type="boolean" checked>
        <span data-bind="text">Set up SSR for landing page</span>
    </div>

    <div class="todo-item">
        <input type="checkbox" data-model="completed"
               data-type="boolean">
        <span data-bind="text">Write unit tests</span>
    </div>
</div>
Key detail: The checked attribute on the checkbox is parsed by the SSR system as completed: true. Use data-model for inputs and data-type="boolean" for checkboxes.

Form Rules

Input Type Attribute Server HTML Parsed State
Text input data-model <input data-model="name" value="John"> "John"
Checkbox data-model + data-type="boolean" <input type="checkbox" data-model="done" data-type="boolean" checked> true
Checkbox (unchecked) data-model + data-type="boolean" <input type="checkbox" data-model="done" data-type="boolean"> false
Select data-model <select data-model="color"><option selected>Blue</option></select> "Blue"
Common Mistake: Using data-bind instead of data-model on form inputs. In SSR mode, data-bind reads textContent, while data-model reads the input's value or checked property.

Nested Data Structures

For complex objects that can't easily be represented as flat DOM values, use a <script type="application/json" data-ssr-state> block:

<div data-component="user-card" data-ssr="true">
    <!-- Hidden JSON block for complex nested state -->
    <script type="application/json" data-ssr-state>
        {
            "user": {
                "id": 123,
                "profile": {
                    "name": "John Doe",
                    "avatar": "/avatars/john.jpg",
                    "preferences": {
                        "theme": "dark",
                        "notifications": true
                    }
                }
            }
        }
    </script>

    <!-- Visible content uses nested binding paths -->
    <img data-bind="user.profile.avatar" src="/avatars/john.jpg" alt="Avatar">
    <h3 data-bind="user.profile.name">John Doe</h3>
    <p>Theme: <span data-bind="user.profile.preferences.theme">dark</span></p>
</div>

The SSR system merges the JSON block into the component's state, giving you deep reactivity on nested properties.

When to Use Each Approach

Approach Use When Example
Inline data-bind Flat values visible in the DOM <span data-bind="name">John</span>
Nested path Shallow nesting, values visible <span data-bind="user.name">John</span>
data-ssr-state JSON Deep objects, config data, non-visible values Preferences, metadata, feature flags
Full Mission Control Dashboard

Machine values carried in data-seed, append pagination, and tombstone deletes over an adopted server-rendered page.

Full Status Page

Status flips, incident posts, and resolves write straight back, with temp ids, tombstone deletes, and an armable rejection to watch rollback happen.