REFERENCE / CORE API
signal()
Creates a signal: a value that remembers who read it, and wakes exactly those readers when it changes — never a component, never a tree.
Signature
signal<T>(initial: T): Signal<T>
Parameters
initial
T
The starting value. Any type. A signal never looks inside its value: replacing it is the only write it sees, so an array or object mutated in place notifies nobody — assign a new one.
Returns
Signal<T> — read and write through .value; read without subscribing through .peek(). A write that leaves the value unchanged (Object.is) is a no-op: nothing downstream runs.
Reading and writing
const count = signal(0);
count.value; // 0 — reading inside a computed, effect or template subscribes
count.value = 1; // notifies exactly the readers of this signal
count.value = 1; // same value: nobody is notified (Object.is)
count.peek(); // 1 — reads without subscribing
In templates
Inside html``, hand over the signal itself, not .value. The template binds exactly one text node (or one attribute) to it, and that node is the only thing updated on a write. Reading .value there bakes the current value in as a constant.
const name = signal('world');
html`<h1>hello, ${name}</h1>`; // hand over the signal: ONE text node follows it
html`<h1>hello, ${name.value}</h1>`; // a plain string: written once, never updates
Writes and the DOM
Writing .value updates the value immediately — the next line reads the new one. The effects that follow it, including every DOM binding, run once in a microtask after the current task, so a burst of writes costs one DOM pass. flushSync() runs the pending effects right now; await tick() waits for them.
const a = signal(1);
const b = signal(2);
effect(() => console.log(a.value + b.value)); // logs 3 at creation
a.value = 10; // the value is 10 right here —
b.value = 20; // — but the effect runs once, in a microtask, after both writes: 30
flushSync(); // or run every pending effect now
Try it
import { signal, html, mount } from '@amojs.dev/core';
const count = signal(0);
const Counter = () =>
html`<button class="counter" onclick=${() => count.value++}>clicked ${count} times</button>`;
const host = document.getElementById('demo');
if (host) mount(Counter, host);