You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Land the library half of the seam locked in #117: recipes inject per-field errors via <Default of={field} errors={ValidationError[]} /> (prop, recipe-pre-gated) and reuse FormFrame’s accessible field composition — instead of each recipe rebuilding FieldShell / FieldErrors / a11y.
Play after the merged form-lib recipes (PR #127 / #123+#124). Those recipes prove BYO errors work; they do not yet exercise this inject path (DefaultFieldRoot still reads ValidationProvider / the store).
Recommended model
Sonnet 5 — the interface is locked; this is careful React/renderer surgery + thinning the example recipes onto it. Escalate only if the renderNodeRules / parts re-sourcing gets subtle.
Injected shape:errors: ValidationError[], per field, keyed by node.path, pre-gated by the recipe (present == show). No show flag.
Mechanism: a prop on ADR-017 re-entry — <Default of={fieldNode} errors={…} />. Not a new context-shaped public seam. renderNodeRules handlers own errors in lexical scope and thread them into parts; any “set once” ergonomic is YAGNI until earned.
a11y (KEEP): control gets aria-invalid + aria-describedby={fieldErrorId(path)}; error list gets id={fieldErrorId(path)}. No role="alert" by default (today’s DefaultFieldErrors still has it — drop it as part of this work).
KEEP: default field composition; movable Errors / Control parts re-sourced from the injected errors; ValidationError + groupErrorsByPath; fieldControlId / fieldErrorId.
Default / field root accepts optional errors?: ValidationError[]. When provided, display + a11y are driven from that prop (not the store). When omitted, current store-backed behavior remains until Cleanup: drop validation-* packages, slim useFormTree, finalize ADRs #126 demotes it (dual path is OK short-term).
Library default field errors: norole="alert".
Example recipes (fieldPresentation.recipe.tsx + RHF/TanStack controls, or a thin follow-up commit) use the inject path and delete duplicated shell/a11y where the library now covers it — keep only form-lib-specific control wiring + error-shape → ValidationError[] (or message) normalization.
Unit/browser tests cover: inject shows errors; a11y attrs track injected errors; omit-prop still works with provider/store until demotion.
Question
Land the library half of the seam locked in #117: recipes inject per-field errors via
<Default of={field} errors={ValidationError[]} />(prop, recipe-pre-gated) and reuse FormFrame’s accessible field composition — instead of each recipe rebuildingFieldShell/FieldErrors/ a11y.Play after the merged form-lib recipes (PR #127 / #123+#124). Those recipes prove BYO errors work; they do not yet exercise this inject path (
DefaultFieldRootstill readsValidationProvider/ the store).Recommended model
Sonnet 5 — the interface is locked; this is careful React/renderer surgery + thinning the example recipes onto it. Escalate only if the
renderNodeRules/ parts re-sourcing gets subtle.Locked contract (#117 — do not reopen)
errors: ValidationError[], per field, keyed bynode.path, pre-gated by the recipe (present == show). Noshowflag.<Default of={fieldNode} errors={…} />. Not a new context-shaped public seam.renderNodeRuleshandlers own errors in lexical scope and thread them into parts; any “set once” ergonomic is YAGNI until earned.aria-invalid+aria-describedby={fieldErrorId(path)}; error list getsid={fieldErrorId(path)}. Norole="alert"by default (today’sDefaultFieldErrorsstill has it — drop it as part of this work).Errors/Controlparts re-sourced from the injectederrors;ValidationError+groupErrorsByPath;fieldControlId/fieldErrorId.ValidationProvider, status hooks, submit-gating — do not re-entrench them. This ticket only adds the inject path and prefers it whenerrorsis passed.Acceptance
Default/ field root accepts optionalerrors?: ValidationError[]. When provided, display + a11y are driven from that prop (not the store). When omitted, current store-backed behavior remains until Cleanup: drop validation-* packages, slim useFormTree, finalize ADRs #126 demotes it (dual path is OK short-term).role="alert".fieldPresentation.recipe.tsx+ RHF/TanStack controls, or a thin follow-up commit) use the inject path and delete duplicated shell/a11y where the library now covers it — keep only form-lib-specific control wiring + error-shape →ValidationError[](or message) normalization.npm run gategreen.Out of scope
validation-*package demotion (Cleanup: drop validation-* packages, slim useFormTree, finalize ADRs #126).Relationships
examples/basic-react/src/{fieldPresentation,rhfFieldControls,tanstackFieldControls}.recipe.tsx(merged via feat(examples): form-library recipes — RHF + TanStack over JSON Schema and Zod, layered and parity-proven #127)