Shared state and props
state() in a <script tibi> is a signal, and one effect tracker serves the whole page: an effect in any component re-runs when any signal it read changes, wherever that signal was created. On top of that, Tibi.shared gives named signals every component can reach, and .name="expr" passes real values (objects, arrays, functions) to child components.Named shared signals
Tibi.shared(name, initial, opts)returns the same signal for the same name everywhere on the page. The first call decides the initial value.persist: truekeeps the value inTibi.storeundershared:<name>(or pass a key such as'prefs:theme'), so it survives reloads;ttlsets its lifetime in seconds (default one year). The stored value loads asynchronously and replaces the initial value unless something already changed it.- Assign a new value to trigger updates (
cart.value = [...cart.value, id]); mutating an array in place doesn't notify.
Signals outside components
Tibi.signal(initial): a standalone signal..valuereads (and subscribes the running effect) and writes;.peek()reads without subscribing;.subscribe(fn)callsfn(value)on every change and returns an unsubscribe function.Tibi.effect(fn): runs now and again whenever a signal it read changes. Returns the runner; call.dispose()to stop it.Tibi.computed(fn): a read-only derived signal.
Component effects are tied to their host element. While the host is out of the document (a t-if branch that's hidden, a page swapped out by client navigation) shared signals drop its effects, so detached DOM is never updated and nothing leaks; they re-run when the host comes back. If it was out long enough for its onUnmount hooks to run, its on(...) and @event listeners come back with it; anything you tore down yourself in onUnmount doesn't.
Passing objects, arrays and functions
Attributes are strings. To hand a child the value itself, prefix the attribute with a dot:
- The binding is reactive: when
productschanges, the child's effects readingprops.productsre-run. - Value props win over a string attribute of the same name;
props.has('x')sees both.props.json('x')returns a value prop as-is. - Value props exist only in the browser: the server render sees the child without them, so render something sensible for
undefined. - From plain JS, set them with
Tibi.setProps(hostElement, { products, onadd }). .namebindings work on component hosts and plain elements in a<script tibi>page or component, including insidet-forrows (nested loops too), where they can pass the row's item:<Card t-for="p of items" .product="p"/>.