Skip to content

data-signals

Declare signals from an object literal or one path at a time. Values merge into the store like a JSON merge-patch: existing sibling paths are kept, plain objects become nested paths, null removes a path.

data-signals="{ count: 0, user: { name: 'Ada' } }"
data-signals:count="0"
data-signals:user.name__ifmissing="'anon'"
part
key optional: a signal path (camelCased, __case changes it)
value required: an object without a key, a value with one
modifier effect
__ifmissing only write paths that do not exist yet; the way to declare defaults next to persist or query-string
__case.kebab keep the key kebab-cased
both forms

is

<div data-signals="{ n: 1, user: { name: 'Ada' } }" data-signals:label="'clicks'" data-signals:user.role="'admin'">
<button data-on:click="$n++"><span data-text="$n"></span> <span data-text="$label"></span></button>
<p><b data-text="$user.name"></b> is <b data-text="$user.role"></b></p>
</div>

A second declaration merges: siblings survive, null deletes.

merge and remove

<div data-signals="{ cfg: { a: 1, b: 2 } }">
<div class="row"><button data-on:click="$cfg = { c: 3 }">$cfg = { c: 3 } (replaces)</button><button data-on:click="el.parentElement.parentElement.setAttribute('data-signals', '{ cfg: { d: 4 } }')">re-declare { cfg: { d: 4 } } (merges)</button><button data-on:click="$cfg.a = null">$cfg.a = null (removes)</button></div>
<pre data-json-signals="{ include: /^cfg/ }"></pre>
</div>

Without it, a declaration would overwrite whatever persist or a query parameter restored a moment earlier.

defaults that yield

theme = (kept), lang = (added)

<div data-signals="{ theme: 'dark' }" data-signals__ifmissing="{ theme: 'light', lang: 'en' }">
<p>theme = <b data-text="$theme"></b> (kept), lang = <b data-text="$lang"></b> (added)</p>
</div>

The value is an expression: read other signals, call functions, use el.

computed at declaration time

doubled once at mount: ; this box was px wide when declared

<div data-signals="{ base: 10 }" data-signals:doubled="$base * 2" data-signals:width="el.offsetWidth">
<p>doubled once at mount: <b data-text="$doubled"></b>; this box was <b data-text="$width"></b>px wide when declared</p>
</div>

Declaration runs once when the element mounts; it is not reactive (use data-computed for that). Declaring the same signal twice is fine; the later one wins unless it has __ifmissing. Paths beginning with _ are excluded from requests by default, which is the convention for browser-only state.

import { signals } from 'sigmx/plugins'

Registering signals adds 142 bytes brotli (153 gzip, 309 minified) on top of the core. See bundle sizes.