Reference: @sigil-dev/runtime

Reference

@sigil-dev/runtime

The macros in your components are compiled away, but the reactive core they compile to lives in @sigil-dev/runtime. You rarely import it directly — reach for it when writing a library, a test, or code that manages effects itself.

import { createSignal, createEffect, batch } from "@sigil-dev/runtime";

Signals

The primitive every macro lowers to:

const count = createSignal(0);

count();              // read — 0
count.set(1);         // write
count.update((n) => n + 1);

const raw = createRawSignal(0);  // no deep proxy

createRawSignal is what $state.raw compiles to: writes notify, but mutating the contents of an object does not.

Reading and writing

  • createMemo(fn) — a derived signal that recomputes only when its dependencies change.
  • tracking() — whether the current code is inside a tracked computation, i.e. whether a read will subscribe.
  • untrack(fn) — run fn without subscribing, for a read you only want the value of.
  • readStore(value) — read a store's value without subscribing.
  • snapshot(value) — a deep copy as plain objects and arrays, without proxies. What $state.snapshot compiles to.

Effects

const dispose = createEffect(() => {
	console.log(count());
});
dispose();

createEffect runs after the current update, re-runs when what it read changes, and returns its cleanup. Also available: createEffectPre (runs before DOM updates), createInspectEffect (a devtools hook), createProfilerEffect (timing), and flushDeferredEffects() to force pending effects to run now.

Batching

batch(() => {
	a.set(1);
	b.set(2);
});

Without batch, two writes notify subscribers twice. With it, they notify once. Anything that sets several signals in a row — a form reset, a swap between two objects — should be batched. tick() returns a promise that resolves after pending effects have run.

Resources

const user = createResource(async (id, { refetch }) => getUser(id), () => userId());

The fetcher comes first, the source signal second. user has .current, .loading and .error; the previous value stays readable while the next one loads, so a page does not flash empty on every refetch. Calling refetch() re-runs the fetcher against the same source.

Collections

ReactiveMap and ReactiveSet — reactive versions of the built-in collections, for when a signal holding an array is not the right shape. The array methods that mutate (push, splice, sort) already work on $state arrays, so these are only worth reaching for with a key-based collection.

Scheduling and scope

  • createRoot(fn) — run fn with a (dispose) => void cleanup for the whole tree. Returns whatever fn returns.
  • withEffectScope(fn) — collect effects created inside fn so they can be disposed together.
  • __asyncBoundary — the marker the compiler emits around async work.

Transitions

mountTransition(element, spec, kind);
removeAnimated(element);

spec is a transition function, or [fn, params]. kind is "in", "out" or "transition", and the call returns a cleanup function. easing.ts exports the standard curves — linear, easeInOutCubic, easeOutQuint and the rest. See Directives and transitions.

SafeHtml

import { SafeHtml } from "@sigil-dev/runtime";

new SafeHtml(userBio);

The wrapper innerHTML requires. A plain string is a type error, which forces the decision about whether content is trusted to be explicit. SIGIL_SAFE is the symbol marking an instance.

Next

Edit this page