Files
lux/examples/web

Lux Web Examples

Interactive browser examples demonstrating Lux compiled to JavaScript.

Quick Start

# 1. Compile the counter example
lux compile examples/web/counter.lux --target js -o examples/web/counter.js

# 2. Start a local server
cd examples/web
./serve.sh

# 3. Open in browser
# http://localhost:8080/index.html

Examples

Counter (String-based)

A simple counter demonstrating the TEA (The Elm Architecture) pattern using string concatenation for HTML:

fn view(model: Model): String = {
    "<div>" + toString(getCount(model)) + "</div>"
}

Counter with Html Module (Type-safe)

The same counter using the type-safe Html module:

fn view(model: Model): String = {
    let count = getCount(model)
    let display = Html.div([Html.class("display")], [Html.text(toString(count))])
    Html.render(display)
}

Compile with:

lux compile examples/web/counter_html.lux --target js -o examples/web/counter_html.js

The Elm Architecture (TEA)

Both examples follow the TEA pattern:

  • Model: Application state (Counter(Int))
  • Msg: Events (Increment, Decrement, Reset)
  • Update: State transitions (Model, Msg) -> Model
  • View: HTML rendering Model -> Html or Model -> String

Available Modules

Html Module

Type-safe HTML construction:

// Elements
Html.div(attrs, children)
Html.span(attrs, children)
Html.button(attrs, children)
Html.input(attrs, children)
Html.h1(attrs, children)
// ... 30+ elements

// Attributes
Html.class("name")
Html.id("id")
Html.href("url")
Html.style("...")
Html.attr("name", "value")

// Events
Html.onClick(handler)
Html.onInput(handler)
Html.on("event", handler)

// Text
Html.text("content")

// Rendering
Html.render(node)      // -> String (for innerHTML)
Html.renderToDom(node) // -> Element (for appendChild)

Dom Effect

Direct DOM manipulation:

fn main(): Unit with {Dom} = {
    match Dom.querySelector("#app") {
        Some(el) => Dom.setTextContent(el, "Hello!"),
        None => ()
    }
}

Available operations:

  • querySelector, querySelectorAll, getElementById
  • createElement, createTextNode, appendChild
  • setTextContent, getTextContent, setInnerHtml
  • setAttribute, getAttribute, addClass, removeClass
  • addEventListener, focus, blur
  • getValue, setValue (for inputs)
  • scrollTo, getWindowSize, getBoundingClientRect

How It Works

  1. Lux code is compiled to JavaScript using lux compile --target js
  2. The HTML page loads the compiled JS
  3. A minimal runtime handles the TEA loop:
    • luxInit_lux() creates initial state
    • luxUpdate_lux(model, msg) handles state updates
    • luxView_lux(model) renders HTML
    • dispatch(msg) triggers updates and re-renders

TEA Runtime

For applications using the Html module with event handlers, you can use the built-in TEA runtime:

Lux.app({
    init: luxInit_lux(),
    update: (model, msg) => luxUpdate_lux(model, msg),
    view: (model, dispatch) => luxView_lux(model),
    root: "#app"
});

Or for string-based views:

Lux.simpleApp({
    init: luxInit_lux(),
    update: (model, msg) => luxUpdate_lux(model, msg),
    view: (model) => luxView_lux(model),
    root: "#app"
});

Development

To modify an example:

  1. Edit the .lux file
  2. Recompile: lux compile <file>.lux --target js -o <file>.js
  3. Refresh the browser