Skip to content

Signals

Signals are nisli’s reactive primitive. A signal holds a value; anything that reads it re-runs when it changes — and nothing else does.

signal

Create state with signal(initial). Read and write through .value.

import { signal } from '@nisli/core';

const count = signal(0);

count.value; // 0 — read through .value
count.value = 5; // write; notifies readers

computed

computed() derives a read-only signal. It is lazy and cached — it recomputes only when a dependency changes.

import { signal, computed } from '@nisli/core';

const count = signal(2);
const doubled = computed(() => count.value * 2);

doubled.value; // 4 — lazy and cached

effect

effect() runs a side effect and re-runs when any signal it read changes. Dependencies are tracked automatically — no dependency arrays.

import { signal, effect } from '@nisli/core';

const count = signal(0);

effect(() => console.log('count is', count.value));
// logs "count is 0" now, and again on every change

Inside html`` templates you read signals implicitly — ${count}, no .value needed. The template subscribes and updates exactly the binding that changed.