bind()
Spread bind(signal, options?) into a form control to wire it to a signal in one line. Covers text inputs (including textarea and select), numbers, checkboxes, and radio groups.
Signature
Section titled “Signature”function bind(signal: Signal<string>): TextBind;function bind( signal: Signal<number>, options: { as: "number" },): NumberBind;function bind( signal: Signal<boolean>, options: { as: "checkbox" },): CheckboxBind;function bind<V extends string>( signal: Signal<V>, options: { as: "radio"; value: V },): RadioBind<V>;Parameters
Section titled “Parameters”| Param | Type | Description |
|---|---|---|
signal | Signal<string | number | boolean> | The signal to read from and write to |
options | { as: "number" | "checkbox" | "radio"; value?: V } | Kind of input; radio also needs the per-radio value |
Returns
Section titled “Returns”A plain props object matching the input kind:
| Kind | Return type | Props |
|---|---|---|
| default | TextBind | { value: () => string, oninput: (e) => void } |
number | NumberBind | { value: () => string, oninput: (e) => void } (coerces) |
checkbox | CheckboxBind | { checked: () => boolean, onchange: (e) => void } |
radio | RadioBind<V> | { value: V, checked: () => boolean, onchange: (e) => void } |
Examples
Section titled “Examples”import { signal, bind, input, textarea, select, option } from "@whisq/core";
const name = signal("");input({ ...bind(name) }); // text
const age = signal(0);input({ type: "number", ...bind(age, { as: "number" }) });
const agreed = signal(false);input({ type: "checkbox", ...bind(agreed, { as: "checkbox" }) });
const role = signal<"admin" | "user">("user");input({ type: "radio", name: "role", ...bind(role, { as: "radio", value: "admin" }) });input({ type: "radio", name: "role", ...bind(role, { as: "radio", value: "user" }) });
const bio = signal("");textarea({ ...bind(bio) });
const tier = signal("free");select({ ...bind(tier) }, option({ value: "free" }, "Free"), option({ value: "pro" }, "Pro"));See Forms guide for the full pattern including validation and reset.
Handler collision (dev warning since alpha.9)
Section titled “Handler collision (dev warning since alpha.9)”Spreading bind(...) and then overwriting one of its declared handlers silently drops the binding. Alpha.9+ catches it with a console.warn in dev (zero cost in production).
// ❌ Direction 1 — spread-first, user-handler-second. Dev: console.warn fires.input({ ...bind(draft), oninput: (e) => track(e), // overwrites bind's oninput});
// ✅ Canonical — put the custom handler BEFORE the bind spreadinput({ oninput: (e) => track(e), // user handler first... ...bind(draft), // ...bind wins visibly; this is what you want});Why “spread bind last” is the convention. The framework can only detect the collision in direction 1 — when bind() sets the handler and the user later overwrites. The reverse case (user handler first, then ...bind()) destroys the user’s handler without trace — by the time the element builder sees the props, the user’s handler is already gone. The warning steers you toward the safe convention: spread bind last so if there is a collision, your own handler visibly “wins” and the absence of the expected bind behaviour is loud instead of silent.
If you deliberately want to augment bind
Section titled “If you deliberately want to augment bind”Chain your handler after reading bind()’s output — that’s a transparent composition that dodges the collision entirely:
const draftBinding = bind(draft);input({ ...draftBinding, oninput: (e) => { draftBinding.oninput(e); // run bind's handler first track(e); // then your own },});The warning fires on symbol-keyed-manifest check in the element builder; the three bind helpers (bind, bindField, bindPath) attach the manifest identically, so the rule is the same on all of them.
Related primitives
Section titled “Related primitives”bindField()— bind a field on an item inside a signal-held array (per-row inputs in lists).bindPath()— bind a field at a nested object path inside a signal-held record (multi-step forms, settings panels).- Event types —
WhisqEventandEventHandlerfor typed custom handlers when the spread isn’t enough.
Docs current to v0.1.0-alpha.9 . All releases →