API Reference

API Reference

All public functions, types, and exports.

Signet(rootEl, dataFn?)

Mount Signet.js onto a root element using a shared global store. All instances created via Signet() on the same page share the same global store object, accessible via .store().

ParameterTypeDescription
rootElElementThe root DOM element to bind.
dataFn() => Object (optional)Function returning initial data. Plain values → signals, getters → computeds.

Returns a SignetApp.

import Signet from 'signet.js';

const app = Signet(document.getElementById('app'), () => ({
  count: 0,
  get doubled() { return this.count * 2; },
}));

// Add to the global store (available to all Signet() instances)
app.store({ theme: 'dark', locale: 'en' });

// Later, tear down
app.unmount();

createApp(data)

Create an app builder (petite-vue style). Accepts a plain object or a factory function. Call .store(), .directive(), and finally .mount() to activate.

ParameterTypeDescription
dataObject | () => ObjectInitial app data. Getters become computeds, methods are auto-bound.

Returns an AppBuilder.

import { createApp } from 'signet.js';

createApp({
  name: 'Alice',
  count: 0,
  get greeting() { return 'Hi, ' + this.name; },
  increment() { this.count = this.count + 1; },
})
  .store({ siteName: 'My App' })
  .directive('focus', ({ el }) => { el.focus(); })
  .mount('#app');

AppBuilder

Returned by createApp(). All methods except .mount() return this for chaining.

.store(obj)

Register shared global state. Properties are added to the prototype of all scopes, so any directive expression can read them. Local scope properties shadow store properties of the same name.

createApp({ count: 0 })
  .store({
    theme: 'dark',
    user: { name: 'Alice', role: 'admin' },
  })
  .mount('#app');

.directive(name, handler)

Register a custom directive available as js-{name}. The handler receives a DirectiveContext and may return a cleanup function.

createApp({ tooltip: '' })
  .directive('tooltip', ({ el, exp, scope, effect }) => {
    const dispose = effect(() => {
      el.setAttribute('title', evaluate(exp, scope));
    });
    return dispose;
  })
  .mount('#app');

.mount(elOrSelector)

Activate the app by walking the root element. Accepts an Element or a CSS selector string. Returns a SignetApp.

const app = createApp({ count: 0 }).mount('#app');
// or
const app = createApp({ count: 0 }).mount(document.body);

SignetApp

Returned by .mount() and Signet(). Provides post-mount control over the app.

Property / Method Type Description
.store(obj) (obj: Object) => void Add more properties to the global store after mounting. New keys are merged into the scope prototype.
.directive(name, fn) (name: string, fn: DirectiveHandler) => void Register a custom directive after mounting. Available in future walks (e.g., dynamically added elements).
.unmount() () => void Dispose all reactive effects recursively, depth-first. Cleans up all signals and event listeners.
.scope Object The reactive scope object. Useful for debugging or programmatically reading/writing state.
const app = createApp({ count: 0 }).mount('#app');

// Read current state (signals need .value)
console.log(app.scope.count.value); // 0

// Update state programmatically
app.scope.count.value = 42;

// Add more store data after mount
app.store({ newProp: 'hello' });

// Tear down
app.unmount();

DirectiveContext

The object passed to custom directive handlers. Use its properties to access the element, the expression, and the reactive environment.

Property Type Description
elElementThe DOM element bearing this directive.
expstringThe raw expression string from the attribute value.
argstring | nullThe colon argument (e.g., "click" for js-on:click).
modifiersstring[]List of dot-separated modifiers (e.g., ["prevent", "once"]).
scopeObjectThe reactive scope object. Contains signals and computed values. Use evaluate(exp, scope) to resolve the expression.
effectfunctionThe effect() function from @preact/signals-core. Use to create reactive subscriptions. The returned disposer is registered as a cleanup function automatically.
// Full custom directive example
.directive('intersect', ({ el, exp, modifiers, scope, effect }) => {
  const once = modifiers.includes('once');
  const callback = evaluate(exp, scope);

  const observer = new IntersectionObserver((entries) => {
    entries.forEach(entry => {
      if (entry.isIntersecting) {
        callback(entry);
        if (once) observer.disconnect();
      }
    });
  });

  observer.observe(el);
  // Return a cleanup function
  return () => observer.disconnect();
})

All Exports

Named exports from both entry points:

Signet.js core

ExportDescription
default (Signet)The Signet(el, dataFn) factory.
createAppThe createApp(data) builder.
setDevModeEnable or disable dev-mode property-resolution warnings. Call before mounting.
resolveSafe dot/bracket path resolver: resolve('user.profile.name', scope). Returns undefined if any segment is null.
evaluateThe expression evaluator: evaluate(expr, scope). Only exported from the default (CSP-safe) entry point.

Re-exported from @preact/signals-core

ExportDescription
signal(value)Create a mutable reactive value. Access via .value.
computed(fn)Create a derived/read-only signal that re-computes when dependencies change.
effect(fn)Run a side-effect function and re-run it whenever signals it reads change. Returns a disposer.
batch(fn)Group multiple signal writes so all effects run once after all writes are done.

setDevMode

import { setDevMode } from 'signet.js';

// Enable warnings for undefined property access in expressions
setDevMode(true);

createApp({ count: 0 })
  // In dev mode: accessing `oops` would log: [Signet] Cannot read 'oops'...
  .mount('#app');

resolve

import { resolve } from 'signet.js';

const scope = { user: { profile: { name: 'Alice' } } };

resolve('user.profile.name', scope);  // 'Alice'
resolve('user.missing.deep', scope);  // undefined (no throw)
resolve('list[2]', { list: ['a','b','c'] }); // 'c'

Scope Helpers

Available in every directive expression as globals:

<!-- Create a new signal inside an expression -->
<div js-scope="{ items: $signal([]) }">...</div>

<!-- Batch multiple updates in an event handler -->
<button js-on:click="$batch(() => { count = 0; name = '' })">Reset all</button>
// Also available as named imports for use outside Signet
import { signal, computed, effect, batch } from 'signet.js';