Skip to main content

The problem

Declarative bindings cover text, attributes, events, and form controls. Some libraries — especially web components — expose property APIs that do not round-trip through HTML attributes. numeric-text updates its display only via .update(), not setAttribute('value', …). You need a reactive primitive that runs imperative sync logic when tracked signals change, with optional cleanup on re-run and teardown.

How Aero helps

Top-level $effect(() => { … }) in <script is:state> registers a side effect compiled to the runtime Effect class (the same scheduler used internally for DOM binds).
Reads of top-level let bindings and reactive props inside the callback subscribe the effect. When those signals change, Aero runs any cleanup returned from the previous run, then runs the callback again.

Syntax

Invalid usage

When to use $effect vs bindings

Keep markup declarative; keep imperative sync in state scripts alongside handlers.

Cleanup pattern

Example: numeric-text wrapper

Web components that animate via .update(value, animated) need a side effect — attribute bindings alone set properties but skip animation semantics.
See the kitchen-sink numeric-text demo for a full page.
Use $root.querySelector(...) to scope DOM lookups to the current page or component instance. bind:this for direct element refs is a planned follow-up.