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. Such a row must declare its type: data-row="<Record>" on the row element plus a matching TypedDict in the .py, so each DOM string is decoded to its real type (an integer id, a boolean flag). Every field a binder reads must be in the record and shipped as data-<field>; an undeclared client-read row is a CompileError. (declui derives the record from your model; the unified idiom's named projection ~ Record[…] is the same declaration.)
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 (kit-internal wiring)¶
Policy: an interactive kit widget is a component; the binder below is its internal wiring, not the public API. Each self-contained widget ships as a situ_ui component — <Tabs>, <DataTable>, <DataGrid>, <Combobox> / <ComboboxMulti>, <Menu>, <CommandPalette> — and the component is how you use it; the kit catalog is the canonical reference. The raw binder is the escape hatch for a bespoke host that can't splice a component (declui's codegen emits one directly, for instance). Either way the runtime holds only presentation state and your data and selection stay in Locals.
| Binder | Component (use this) | App-owned state |
|---|---|---|
:tabs |
<Tabs> |
— (bar generated from data-tab panels) |
:table="rows" |
<DataTable> |
Local[list]; header-click sort |
:datagrid="rows" + :datagridsel="sel" |
<DataGrid> |
Local[list] + Local[set] — sort + filter + pagination + selection |
:combobox="value" |
<Combobox> / <ComboboxMulti> (multi via data-multi) |
Local[str] / Local[set] |
:menu |
<Menu> |
— (items keep their compiled @click) |
:palette |
<CommandPalette> |
— (⌘K overlay) |
The other two runtime binders have no self-contained component — you compose them onto your own markup (like :each), so they stay first-class author binders:
| Binder | Meaning | App-owned state |
|---|---|---|
:sortable="list" |
pointer drag-reorder over a :each list (<Sortable> is a thin convenience wrapper) |
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.