Skip to content

Binders & events

The complete shorthand vocabulary a component template may use. Every token is compiled — none of these are interpreted at runtime.

Events

Event Fires on Notes
@click click allowed everywhere (incl. :each rows)
@dblclick double click top-level only
@submit form submit preventDefault() applied; sends the form's fields with a command — the idiomatic submit (never @click on a button whose default type=submit would reload)
@input input top-level only; pairs with :bind for validate-as-you-type
@escape Esc keydown top-level only

The value is an action program: ;-separated signal = expr assignments and handler calls — see Handlers & commands.

Core binders

Binder Meaning Constraint
:text="expr" textContent tracks the expression
:show="expr" element hidden unless truthy; focuses a child [autofocus] on reveal
:class="name: expr" toggle one class on a condition
:attr="name: expr" set/remove an attribute (falsy/None removes; True → empty attr)
:bind="signal" two-way input binding; type=number inputs coerce to JS numbers; the focused field is never repainted mid-keystroke the signal must be Local
:each="row in coll" the keyed client list reconciler coll is a Local[list] (or an enclosing row's field); the binder goes on a wrapper — never on the same element as other binders
:tree="row.children" self-recursive row template (recursive lists, comment threads) inside a :each
:autohide="signal" clear a status signal back to its default after ~4 s

Inside a :each row

Row-scoped binders compile against the row object: :text/:show/:class/:attr/:bind all work with t.field reads; events are restricted to @click/@submit. A row's identity is its id field (reconciliation is keyed on it). Server-rendered rows expose fields to the client through data-* attributes — t.field in a binder on a data-id row reads the row's dataset.

Transport binders

Binder Meaning Requires
:virtual="handler(scroll)" a windowed viewport: only the visible rows in the DOM, fetched from the mount's /window route a server handler + a Local scroll signal; mount_component(window_template=...)

Widget binders (the optional kit runtime)

These mark a host for a runtime in situ_ui's widgets.js — presentation state lives in the runtime, your data and selection stay in Locals:

Binder Widget App-owned state
:tabs tab bar generated from data-tab panels
:table="rows" sortable table body Local[list]
:datagrid="rows" + :datagridsel="sel" sort + filter + pagination + row selection Local[list] + Local[set]
:combobox="value" searchable listbox (single or multi via data-multi) Local[str] / Local[set]
:menu WAI-ARIA menu button — (items keep their compiled @click)
:palette ⌘K command overlay
:sortable="list" pointer drag-reorder Local[list]
:cells="grid" the spreadsheet formula engine — the one sanctioned runtime interpreter, for user-typed formulas Local[dict]

The island feature-detects each runtime (S.tabs && S.tabs(el)), so pages that don't load widgets.js are unaffected.

The unified idiom (opt-in)

With mount_component(..., unified=True):

Construct Meaning
{ expr } one interpolation — server-rendered or live, derived from the expression's sites
:each="t in coll ~ [f1, f2]" the loop with its wire projection: the complete per-row field list allowed to cross to the browser; anything else is a CompileError

See The unified idiom.