Server-Side Rendering (SSR) FULL

Integrate server-rendered HTML with WildflowerJS components for fast first paint and SEO.

Meta-Framework Showcase: Most examples in this documentation run directly within the site using WildflowerJS itself - demonstrating the framework's meta-capabilities. SSR examples run in isolated environments due to server-rendering requirements.
Production Ready: WildflowerJS SSR provides complete state hydration, content protection, and exact functional equivalence between server-rendered and client-rendered components.

SSR Overview

WildflowerJS SSR enables you to:

  • Preserve server-rendered content - No flashing or re-rendering
  • Parse state from DOM - Components automatically extract their state from server HTML
  • Maintain interactivity - Actions, events, and dynamic updates work normally
  • Optimize performance - Skip unnecessary initial renders and binding updates

SSR Philosophy

"Server content is perfect - don't recreate it, just protect and enhance it"

WildflowerJS SSR follows a protection-first approach where server-rendered content is preserved and enhanced rather than replaced.

Basic Setup

Enable SSR by adding the data-ssr="true" attribute to your components:

SSR Example Basic Server-Side Rendered Component Open Full Example ↗
Server-Rendered HTML:
<div data-component="user-profile" data-ssr="true">
    <h2 data-bind="name">John Doe</h2>
    <p data-bind="email">john@example.com</p>
    <p data-bind="role">Administrator</p>
    <button data-action="editProfile">Edit Profile</button>
</div>
SSR Difference: This example runs in an isolated environment to demonstrate true server-side rendering. Other framework examples in this documentation run directly within the main site using WildflowerJS's meta-framework capabilities.
Automatic State Hydration: The component's state will be automatically populated with name: "John Doe", email: "john@example.com", and role: "Administrator" from the server-rendered content.

State Hydration

WildflowerJS automatically parses server-rendered content into component state:

Data Type Support

Data Type Attribute Example HTML Parsed Value
String none <span data-bind="name">John</span> "John"
Number data-type="number" <span data-bind="age" data-type="number">25</span> 25
Boolean data-type="boolean" <span data-bind="active" data-type="boolean">true</span> true
JSON data-type="json" <span data-bind="config" data-type="json">{"theme":"dark"}</span> {theme: "dark"}
HTML data-type="html" <div data-bind="content" data-type="html"><b>Bold</b></div> "<b>Bold</b>"
SSR Example Data Type Hydration Demo Open Full Example ↗
Server-Rendered HTML with Data Types:
<div data-component="data-showcase" data-ssr="true">
    <div data-bind="username">johndoe</div>
    <div data-bind="score" data-type="number">1250</div>
    <div data-bind="verified" data-type="boolean">true</div>
    <div data-bind="metadata" data-type="json">{"theme":"dark","lang":"en"}</div>
    <button data-action="showState">Show Current State</button>
</div>
State Hydration: Click "Show Current State" to see how the framework automatically parsed the server-rendered content into component state with proper data types.

List SSR

SSR lists preserve server-rendered content while still supporting the full dynamic behavior:

SSR Example SSR List with Dynamic Functionality Open Full Example ↗
Server-Rendered List HTML:
<div data-component="user-list" data-ssr="true">
    <h3>Users (<span data-bind="users.length">3</span>)</h3>
    <div data-list="users">
        <template>...</template>
        <!-- Server-rendered list items -->
        <div class="user-card">Alice Johnson - alice@example.com</div>
        <div class="user-card">Bob Smith - bob@example.com</div>
        <div class="user-card">Carol Davis - carol@example.com</div>
    </div>
    <button data-action="addUser">Add Random User</button>
</div>
Performance Magic: The 3 server-rendered users are preserved and never re-rendered. Try "Add Random User" to see new users appended to the server-rendered list.
Performance Benefit: The server-rendered list items are never cleared or re-rendered. New items are appended, and the list count updates automatically.

Hidden Fields: data-seed

State hydration parses what the page displays. Data your components need that never appears as text, record ids, API paths, permission flags, cannot be recovered from the DOM. The data-seed attribute carries those fields as a small JSON object, rendered by the server on the element the data belongs to:

<!-- On the component root: unrendered state fields -->
<div data-component="user-profile" data-ssr="true" data-seed='{"userId":42}'>
    <h2 data-bind="name">Ada Lovelace</h2>
</div>

<!-- On list item roots: unrendered item fields, most often the identity -->
<div data-list="users">
    <template>...</template>
    <div class="user-card" data-seed='{"id":11}'><span data-bind="name">Alice Johnson</span></div>
    <div class="user-card" data-seed='{"id":12}'><span data-bind="name">Bob Smith</span></div>
</div>

Seed fields merge into the parsed state and win any overlap with display text, since the attribute is the machine value and the text is the formatted one. A count rendered as "250+" can carry data-seed='{"count":250}' and hydrate as a number. Each datum still exists once in the HTML: visible fields as text, hidden fields on the element they describe.

Also for queries: data queries adopting SSR content read the same attribute for row and record fields. One convention, everywhere the DOM is the seed.

Mixed Components

You can mix SSR and regular components on the same page:

SSR Example SSR + Client Components Together Open Full Example ↗
Mixed Component Types:
<!-- SSR Component - content preserved from server -->
<div data-component="server-stats" data-ssr="true">
    <h3>Server Statistics</h3>
    <p>Uptime: <span data-bind="uptime">24 days, 15 hours</span></p>
    <p>Memory: <span data-bind="memory">2.4 GB</span></p>
</div>

<!-- Regular Component - dynamically rendered -->
<div data-component="client-stats">
    <h3>Client Statistics</h3>
    <p>Session Time: <span data-bind="sessionTime"></span></p>
    <button data-action="incrementClicks">Click Me!</button>
</div>
Best of Both Worlds: Server-rendered content for SEO and instant visibility, plus dynamic client components for interactivity. Notice how the session timer updates in real-time!

Best Practices

✅ Do's

  • Use for above-the-fold content - Critical content that needs immediate visibility
  • Preserve semantic HTML - Server content should be meaningful without JavaScript
  • Include proper data types - Use data-type for numbers, booleans, and JSON
  • Structure list items correctly - Binding elements should be children of list items
  • Test without JavaScript - Ensure content is accessible when JS is disabled

❌ Don'ts

  • Don't SSR everything - Use for content that benefits from immediate rendering
  • Don't modify SSR content - Let the framework handle state synchronization
  • Don't mix rendering paradigms - Be consistent within each component
  • Don't skip templates - SSR lists still need templates for dynamic additions

Edge Cases

⚠️ Falsy Values: Empty strings, 0, and false are preserved correctly:
<span data-bind="count" data-type="number">0</span>state.count = 0
<span data-bind="enabled" data-type="boolean">false</span>state.enabled = false
Full Status Page

Services, incidents, and a notice read straight out of server-rendered HTML with no loading flash, then kept live on polling, focus, and reconnect.

Full Mission Control Dashboard

A KPI header and orders table adopted from server-rendered HTML, with machine values carried in data-seed.