Live HTML · In depth

page, component, state, action, view

Small TypeScript decorators declare routes, reusable component ownership, reactive server state, browser-callable actions, and collection item views.

Explain it like I’m five

The simple mental model

The decorators are small labels: page says where a screen lives, component says what can be reused, state says what may change, action says what the browser may request, and view describes repeated items.

When it fits

When should I use it?

Use them to make server-rendered ownership visible next to the class member it affects instead of maintaining a separate routing and binding manifest.

A practical API pattern

Follow the example

Taken directly from the complete realtime recipe, including its setup and tests.

Read this article as Markdown

TSX
import { action, page, start, state, type LiveHtmlStartOptions } from 'redweb';
import { runApp } from './run-app';

@page('/', { css: 'app.css', shared: true })
export class CounterPage {
    @state() count = 0;

    @action()
    increment() { this.count += 1; }

    render() {
        return (
            <main class="home">
                <h1>A counter owned by the server</h1>
                <p>Open this page in two tabs. Either button updates both.</p>
                <button rw-click="increment">
                    Count {this.count}
                </button>
            </main>
        );
    }
}

export function createApp(options: LiveHtmlStartOptions = {}) {
    return start(CounterPage, { port: Number(process.env.PORT ?? 8181), templateRoot: __dirname, ...options });
}

if (require.main === module) runApp(createApp);
  1. 1

    @page registers the outer route and page policy.

  2. 2

    @state and @action expose only explicitly declared reactive behavior.

  3. 3

    The counter renders ordinary TSX over its state; changes reach both tabs because the page explicitly opts into shared state. Use the chat recipe to explore reusable class components.

Surface area

Methods and members

page(path, options?)

Registers a unique route plus template, CSS, sharing, metadata, caching, and live/static behavior.

component()

Marks a class as a reusable state/action/lifecycle namespace.

component(render)

Creates a concise synchronous function component for stateless reusable HTML.

state(options?)

Publishes reassigned values; writable state may also receive bounded browser input.

action({ input? })

Explicitly exposes one method to rw-click or rw-submit. An optional Standard Schema input validates and transforms one submitted argument before invocation; ActionInput<typeof schema> describes its output. Invalid input stays recoverable, while validator bugs remain server failures. Undecorated methods stay unreachable.

rw-status="action"

Optional component-scoped placement for built-in action feedback. Without a slot, buttons/forms get an automatic status message. Pending duplicates from one control are suppressed; late responses preserve changed drafts and replacement forms. Disconnected actions are never queued or replayed.

view(stateName)

Renders each item of one decorated array for an rw-each collection.