Why this works
ShadowJS has no private path for its own features.
ShadowJS has no private path for its own features. useSignal, useMemo, useEffect, useStore,
useResource, mapArray, useSelector, contexts and the router's hooks import only
@shadow-js/core/extend (or other public hooks); the web control flow (Show, For, Portal,
Dynamic, Suspense, head tags) is built on public core hooks and the renderer building blocks that
@shadow-js/web/extend exports. If
something a built-in needs is unreachable for you, that is a bug in the framework, not a limit of the
design.
| Entry | For | Exports |
|---|---|---|
@shadow-js/core |
everyday hooks | useStore, useMemo, useEffect, createRoot, onCleanup, untrack, mapArray, isServer, isDev, ... |
@shadow-js/core/extend |
new primitives | cells, computations, owners, scheduling, diagnostics |
@shadow-js/web |
everyday components | render, hydrate, Show, For, Portal, insert, template, ... |
@shadow-js/web/extend |
new components and renderers | regions, reconciliation, hydration scope, URL policy, warnings |
The two extend entries are the surface the built-in components and hooks are written against. Pin your
@shadow-js/* versions together.
@shadow-js/core/extend at a glance#
| Group | Exports | What they do |
|---|---|---|
| Cells | createSignalNode(value, equals, name?), readSignal(node), writeSignal(node, next, options?), track(source), notify(source), markObservers |
storage of a value with observers; read subscribes the running computation; write compares with equals and notifies |
| Computations | createComputation({ kind, fn, ... }), readComputation(node), refresh(node) |
memos and effects; owned and disposed with their owner |
| Ownership | Owner, createOwner(parent?), disposeOwner(owner), addCleanup(owner, fn), handleError(error, owner) |
lifetimes, cleanups (newest first), error routing |
| Registers | currentOwner(), currentListener(), isTracking(), isComputingMemo(), runInScope({ owner, listener }, fn) |
read the current scope; set it with restore in finally |
| Scheduling | batch, flush, flushSync, schedule, group |
when effects run |
| Diagnostics | warn(code), ShadowError, MESSAGES, formatMessage, setWarningListener, resetWarningDedupe |
the same codes and listeners the built-ins use |
@shadow-js/web/extend at a glance#
| Group | Exports | What they do |
|---|---|---|
| Regions | createRegion(parent, anchor, initial), bindRegion(region, value), removeRegion(region) |
the machinery of insert: a span of children kept in sync with a value |
| Reconciliation | reconcileNodes(parent, prev, next, end) |
minimal-move reorder of a node list |
| Hydration scope | nextKey, enterComponent, childScope, withScope, currentScope, createRootScope, resourceKey |
deterministic keys shared by server and client |
| Claiming | claimElement(key), isClaiming(), takeRegion(parent, anchor) |
adopt server elements while hydrating |
| Policy | isUnsafeUrlAttribute(name, value), warnOnce(code, detail), HTML_NS, SVG_NS, MATHML_NS |
the runtime's URL rule and web warnings (codes UNSAFE_URL_BLOCKED, INVALID_ATTRIBUTE_NAME) |
| Streaming | StreamContext, StreamBoundary, StreamSink |
what Suspense uses to defer boundaries on the server |