Quick Start

Dataflow is a lightweight reactive JavaScript library heavily inspired by Observable Framework. It brings reactive programming to plain HTML pages with minimal overhead - the runtime (including JSX support) is only !

Just add a single is="reactive" attribute to any script tag and it becomes reactive. That's it.

It works like a spreadsheet: just reference a value from another reactive script tag, and the plumbing happens automatically. For most cases, you don't need setState, Redux, or manual subscriptions - just declarative dependencies. When you do need state that flows back up the graph, there's mutable.

Document order does not matter, all reactive scripts will be topologically sorted and turned into a DAG before execution.

The transformation can happen at build time, at runtime on the server, at the edge, or even client-side using a service worker. See the Setup page for details.

Example

A live clock using a generator that yields the current time:

<script type="module" is="reactive">
`The current time is ${new Date(now).toLocaleTimeString("en-GB")}.`
</script>

Expressions and Display

A single expression automatically displays its result:

<script type="module" is="reactive">
1 + 2
</script>
Note: Unlike Observable, a semicolon on the end of a single expression does not change how it behaves. A single expression is always a singles expression regardless of optional semicolons. Prettier will not break anything.

Statements like variable declarations don't display anything - they just define values for other blocks to use:

<script type="module" is="reactive">
const foo = 1 + 2;
</script>

The variable foo is defined but nothing is displayed.

For explicit control, use the display function. You can call it multiple times:

<script type="module" is="reactive">
for (let i = 0; i < 5; ++i) {
    display(i);
}
</script>

Imports

All top-level declarations (including imports) are shared within the same reactive scope. By default, the whole page is a single scope. For isolated scopes, see Reactive Islands.

Common APIs like display, view, input, mutable, now, etc. are implicitly available - no import needed. Just use them directly in any reactive script.

Note: All the examples from now on will not show the enclosing reactive script tag

DOM Nodes

If an expression evaluates to a DOM node, the node is inserted into the page. Use this to create dynamic content.

document.createTextNode("[insert chart here]")

JSX

JSX is supported for creating DOM elements with a familiar syntax. Under the hood, JSX compiles directly to native DOM methods using the @bodar/jsx2dom library - no virtual DOM, no framework overhead.

Note: Observable Framework uses template literals (html`...`) for HTML. Dataflow uses JSX which provides better IDE support, type checking, and a more React-like developer experience.

For example, here's a component that displays a greeting:

const greeting = (name) => <i>Hello {name}!</i>
greeting("World")

JSX attributes work as expected, including dynamic values:

const color = "blue";
<span style={`color: ${color}; font-weight: bold`}>Styled with JSX</span>

Reactive Inputs

The view function creates reactive inputs. When the input changes, dependent code re-runs:

const name = view(<input name="name" type="text" value="World"/>);
`Hello, ${name}!`

See the Inputs page for more input types and patterns, and the Reactivity page for generators, invalidation, and other reactive patterns.