system.cssthe engine GitHub

The recipe

The recipe — every component follows it

  1. One signal namespace holds all state. data-signals:ns="{ ... }" on the wrapper. Everything reads/writes $ns.field.
  2. Bake the structurally-constant DOM. Datastar has no client-side loop or template. A month grid always has 42 day cells; a numpad has 12 keys; a combobox list has N options. Emit those nodes at author/build time (a Python f-string loop, a server template — anything that runs before the page ships). The DOM shape is fixed; only its content and state change.
  3. Bind each baked node reactively — data-text, data-show, data-class, data-attr, data-style, data-on.
  4. Props down via pure helpers; events up via data-on. Plain JS functions take signal values as arguments and return a value/boolean (cellIsToday($cal.v, i), cbFilter($cb.q)). They never read globals or mutate — they're props-down. data-on:click is events-up: it mutates the signal, the bindings recompute.
  5. Layout from system.css primitives in the markup; the rest from the API. See "Don't hand-roll layout" below.