cDOM (Experimental)

A declarative, expression-based way to build reactive UIs.

Overview

The Computational DOM (cDOM) is a revolutionary way to describe user interfaces using reactive expressions that feel as natural as spreadsheet formulas. Instead of writing complex JavaScript logic to update your UI, you define the relationships between your data and your elements.

If you wish to explore the implementation further, you can visit the GitHub repository, browse the cdom directory, and check out the cdom unit tests.

Advantages

🛡️ Enhanced Security

cDOM strictly avoids eval() and direct HTML injection. By using a custom high-performance parser and a registry of pre-defined helper functions, it provides a safe sandbox for dynamic content, making it highly resistant to XSS attacks.

🤖 LLM Friendly

Large Language Models excel at generating structured data and formulaic expressions. cDOM's declarative nature and concise syntax (CDOMC) make it far easier for AI to generate correct, bug-free UI components compared to traditional JavaScript-heavy frameworks.

How It Works

cDOM uses a powerful path-based resolution system to link UI elements directly to reactive state.

cDOM paths can range from simple property access to complex, nested transformations. Consider this example:

currency(sum(map(filter($/orders, eq(_/status, 'paid')), _/total)...))

Anatomy of a Path

A path in cDOM is a powerful string that describes how to navigate your reactive state and apply transformations.

Paths always start with a $.

Examples

Representing a shopping cart total with reactive expressions:

// Example CDOM structure. Note: cDOM paths are not quoted, a special parser is used for files eding  in .cdom
{ 
    div: {
        children: [
            { h2: "Shopping Cart" }, // Static header
            { ul: { 
                // Map over the items in the cart: name - $price
                children: $map(/cart/items, li(_/name, ' - $', _/price))
            }},
            { p: { 
                class: "total",
                // Calculate the total by summing item prices
                children: ["Total: $", $sum(/cart/items...price)]
            }}
        ]
    }
}

Expected HTML Output

<div>
    <h2>Shopping Cart</h2>
    <ul>
        <li>Apple - $1.00</li>
        <li>Orange - $2.00</li>
    </ul>
    <p class="total">Total: $3.00</p>
</div>

Actual Rendering

Shopping Cart

  • Apple - $1.00
  • Orange - $2.00

Total: $3.00

Comparison to Excel

Think of your UI as a spreadsheet. In Excel, if Cell C1 has the formula =A1+B1, C1 updates automatically whenever A1 or B1 changes.

cDOM brings this exact paradigm to the web. Every attribute and text node can be a "cell" that computes its value based on other "cells" (reactive signals).

Feature Excel cDOM
Reactive Unit Cell Signal / State Proxy
Formulas =SUM(A1:A10) sum($/items...)
Path Resolution Cell References (A1, $B$2) JSON Paths (./name, $/global)
Recalculation Automatic on change Automatic on change

Events and Interaction

cDOM is designed to handle user interactions gracefully, whether in a traditional standalone application or in a dynamic, LLM-driven environment.

Manual Implementation (Standalone Apps)

Developers can use the cdom-on: directive to bind expressions directly to DOM events. This allows for clear, declarative event handling that updates local state or calls helper functions.

<button cdom-on:click="increment(/count)">Click Me</button>

LLM-Generated Interaction

Because cDOM represents the UI as data, an LLM can easily generate event handlers to register its interest in specific user actions. Instead of writing complex JavaScript observers, the LLM simply includes event handlers that notify the server.

// Example of an LLM 'registering' for a click event. Note the fetch url is quotes so it is not mistaken for a CDOM signal or state reference.
{ 
    button: {
        "cdom-on:click": "fetch('/api/notify', { method: 'POST', body: { $event } })",
        children: ["Notify LLM"]
    }
}

By generating these attributes on specific elements, the LLM effectively "subscribes" to the behavioral data it needs to reason about the user's next steps. The $event placeholder ensures the LLM receives the full context of the interaction.

The Interaction Lifecycle

🤖 LLM-Driven Flow

  1. LLM generates the initial UI structure as JSON.
  2. HTTP Server receives the JSON and serves it to the Client.
  3. Client renders the cDOM and activates local reactivity.
  4. User Interacts (e.g., clicks a 'notify' button).
  5. Client sends the interaction data back to the HTTP Server.
  6. HTTP Server relays the event context to the LLM.
  7. LLM processes the event and sends a Patch/Update back to the HTTP Server.
  8. HTTP Server relays the update to the Client.
  9. Client merges the update, instantly refreshing the UI.

🏠 Standalone Flow

  1. Static cDOM is defined in the Client's source code or local files.
  2. Client activates the UI locally on page load.
  3. User Interacts (e.g., clicks a local toggle).
  4. Local State is updated immediately.
  5. UI Recalculates based on reactive expressions (0 latency).
  6. HTTP Server is only contacted for persistence or traditional API calls.

Helper Functions

cDOM comes with a rich set of built-in helpers that cover most common UI logic and data transformations. Developers can also register their own custom functions to extend cDOM's capabilities:

// Register a custom function
cDOM.register(f, name=f.name);

For security and deterministic behavior, cDOM operates in a sandbox. It cannot access globalThis or arbitrary window properties. Only functions explicitly registered via cDOM.register() are available for use within cDOM expressions.

Math

Basic arithmetic and mathematical operations.

+, add, -, sub, *, mul, /, div, round, ceil, floor, abs, mod, pow, sqrt

Stats

Aggregate results from arrays of numbers.

sum, avg, min, max, median, stdev, var

String

Text manipulation and formatting.

upper, lower, trim, capitalize, titleCase, contains, startsWith, endsWith, replace, split, len, join, default

Array

Collection processing and iteration.

count(len), map, filter, find, unique, sort, reverse, first, last, slice, flatten, join

Logic & Comparison

Boolean logic and value comparison.

if, and(&&), or(||), not(!), eq(==, ===), neq(!=), gt(>), lt(<), gte(>=), lte(<=), between, in

Conditional Aggregates

Statistical functions that take a filter predicate.

sumIf, countIf, avgIf

Formatting

Display helpers for various data types.

number, currency, percent, thousands

DateTime

Date creation, parsing, and arithmetic.

now, today, date, formatDate, year, month, day, weekday, addDays, dateDiff

Lookup

Data retrieval from indexed structures.

lookup, vlookup, index, match

State Mutation

Directly modify reactive state from event handlers.

set, increment(++), decrement(--), toggle(!!), push, pop, assign, clear

Network

Data fetching and network requests.

fetch(url, options?)

The fetch helper simplifies network requests by handling body serialization. If the body is a non-null object, it is automatically stringified as JSON and the Content-Type is set to application/json (if not already set). Otherwise, the body is converted to a string and Content-Type is set to text/plain.