Reactive Character Counter

A textarea, a counter, and a submit button - each declared with `bind` against one shared variable, no event wiring.

A textarea, a live character count that color-changes near the limit, and a submit button that disables when over the limit or empty. Three independent elements, no direct references between them - each one declares what it shows in terms of a single shared reactive variable.

Example: Type to see the counter update live
<div class="char-counter">
    <textarea rows="3" placeholder="Write a short message…"
              _="bind $msg to me"></textarea>
    <div class="char-counter-meta">
        <span class="counter"
              _="live put $msg.length + ' / 280' into me
                 bind .warn to $msg.length > 240
                 bind .over to $msg.length > 280"></span>
        <button _="bind @disabled to $msg.length > 280 or $msg is empty">
            Post
        </button>
    </div>
</div>
Try It!

The whole pattern is four binds and one live:

bind $msg to me           -- on the textarea

live put $msg.length + ' / 280' into me   -- on the counter
bind .warn to $msg.length > 240
bind .over to $msg.length > 280

bind @disabled to $msg.length > 280 or $msg is empty   -- on the button

bind $msg to me two-way-binds the textarea's value to a global reactive variable $msg. Type into the textarea, $msg updates. Set $msg from anywhere, the textarea updates. Now the counter and the button can both subscribe to it without ever touching the textarea directly.

The counter combines one live and two binds:

The submit button has just one bind:

The mental model: every UI element declares what it shows in terms of reactive variables, and the runtime wires the dependencies for you. bind covers four bindings:

Form Effect
bind $var to me Two-way: variable ↔ input value
bind .className to [boolean] One-way: class present iff expression true
bind @attrName to [boolean] One-way: attribute present iff expression true
bind @attrName to [expression] One-way: attribute set to expression result

Adding a fourth element that depends on $msg (a preview, a word count, an emoji indicator) requires zero changes to anything else - just write its own bind or live against $msg.