Browse docs
Browse docs
Released 2026-05-10 · Performance + correctness
Restores Dashforge's core promise of "fewer renders than plain RHF" via
per-field subscriptions, fixes two hook-rules / lifecycle bugs, and
tightens dependent-field UX. This is the release the
0.2.0-beta public-API freeze builds on.
| Package | What changed |
|---|---|
@dashforge/ui-core | DashFormBridge gains subscribeField and unregister (both optional, backwards-compatible at the time). |
@dashforge/forms | New useDashFieldMeta hook. Bridge identity stabilized — per-field listeners replace global version bumps. |
@dashforge/rbac | New useRbacOptional — non-throwing variant of useRbac, used by access-aware UI hooks. |
@dashforge/ui | All form components migrate to per-field subscribe; deferred unregister on real unmount; auto-reset policy. |
useDashFieldMeta(name) in @dashforge/forms — the canonical way to
subscribe a UI component to its own field's value / error /
touched / dirty / submitCount / allowAutoError. Backed by
useSyncExternalStore with a primitive-equality cache, so unrelated
field edits never re-render the consumer.useRbacOptional() in @dashforge/rbac — non-throwing version of
useRbac() that returns null when RbacProvider is absent.bridge.subscribeField(name, listener) — per-field subscription
primitive (the ?: optional became required in
0.2.0-beta).bridge.unregister(name) — releases engine + RHF state for a field;
UI components call it on real unmount to prevent the getNode(name)
memory leak after dynamic field removal.DateTimePicker.layout prop — 'stacked' (default) or 'inline'.useContext(DashFormContext) consumer to re-render. The
bridge is now memoized on its structural deps; reactivity is delegated
to per-field listeners + useDashFieldMeta.void bridge?.errorVersion; global-subscribe trick with a single
useDashFieldMeta(name) call.Select / Autocomplete — when loaded
options can no longer resolve the current form value, the value is
auto-reset to null instead of being silently preserved. This is a
behavior change: previously a blank control could still submit a stale
id.useAccessState — the hook used to call
useRbac() inside a try/catch, changing the hook count between renders
when RbacProvider was absent. Fixed via useRbacOptional().queueMicrotask cleanup pattern ensures field cleanup runs
only on genuine unmount, not on every keystroke.The unresolved-value auto-reset is a behavior change — if you relied on a stale id surviving an options reload, that no longer happens. Otherwise no code change required.