66 KiB
@suaveplan/react-forms - React forms library — ApiClient/Auth contexts, ValidationEngine, useFormValidation/useDomainForm with field rendering, createDomainForm factory (with three escape hatches), four recipes (wizard, repeating-fieldset, conditional, async-search), MoneyInput + Field re-exports, and a TranslationKey-typed validator suite (sync + async + composers).
Summary
React forms library for the Suaveplan ecosystem. Wraps
react-hook-form + Zod with a primitives + factory + recipes
architecture: every user-facing string is typed TranslationKey,
every error code is registered with @suaveplan/error, every
lifecycle event emits OTel telemetry.
Wave 5b adds the field-rendering layer, the createDomainForm
factory (with three escape hatches), four recipes (wizard,
repeating-fieldset, conditional, async-search), and the
MoneyInput primitive on top of Wave 5a's contexts + validation
engine + validator suite.
Documentation tree
- api-client-context — (no submodules) - use-api-client — React hook that reads the active `…
- api-client-context — (no submodules) - use-api-client — React hook that reads the active `…
- use-api-client — React hook that reads the active
ApiClientfrom the surrounding<ApiClientProvider>and returns it typed as the con…
- auth-context — (no submodules) - use-auth — React hook that reads the active `AuthCo…
- auth-context — (no submodules) - use-auth — React hook that reads the active `AuthCo…
- use-auth — React hook that reads the active
AuthContextValuefrom the surrounding<AuthProvider>and returns it typed as `Auth…
- use-domain-form — (no submodules)
- use-domain-form — (no submodules)
- use-form-validation — (no submodules)
- use-form-validation — (no submodules)
- validation-engine — (no submodules)
- cross-field-rule — Convenience factory + helper for declaring
CrossFieldRulevalues. Cross-field rules are the second pipeline phase ins… - server-error-mapper — Bridges server-side validation envelopes into the engine's per-field
ValidatorFailureshape. When a form's `submit.on… - validation-engine — (no submodules)
- cross-field-rule — Convenience factory + helper for declaring
- error-codes — Registers the thirteen stable error codes used by
@suaveplan/react-formsunder theREACT_FORMSnamespace via `defin… - react-forms-error — Defines the base
ReactFormsErrorclass shared by every error path in@suaveplan/react-forms. Extending the project… - create-domain-form — Declarative typed-form factory. Wraps
useDomainForm+<RHF FormProvider>+ the layout dispatcher into a single comp…- create-domain-form — Declarative typed-form factory. Wraps
useDomainForm+<RHF FormProvider>+ the layout dispatcher into a single comp…
- create-domain-form — Declarative typed-form factory. Wraps
- field-config —
FieldConfigdiscriminated union, per-kind Zod schemas, and thevalidateFieldConfig/validateFieldConfigMaphelpe…- field-config —
FieldConfigdiscriminated union, per-kind Zod schemas, and thevalidateFieldConfig/validateFieldConfigMaphelpe…
- field-config —
- render-field — Single-field renderer used by
useDomainFormandcreateDomainFormto turn a typedFieldConfiginto a<Field>cha…- render-field — Single-field renderer used by
useDomainFormandcreateDomainFormto turn a typedFieldConfiginto a<Field>cha…
- render-field — Single-field renderer used by
- locales — Bundled translation strings shipped with
@suaveplan/react-forms.- augmentation — Side-effect-only TypeScript module that augments
@suaveplan/react-i18n'sContributedTranslationKeysinterface with… - locales — Bundled translation strings shipped with
@suaveplan/react-forms. - translation-keys —
translation-keys.tsis the codegen-emitted string-literal union of every translation key contributed by `@suaveplan/r…
- augmentation — Side-effect-only TypeScript module that augments
- observability — (no submodules)
- react-forms-metrics — (no submodules)
- field — (no submodules)
- field — (no submodules)
- money-input — Locale-aware currency input wrapping
@suaveplan/react-ui's<Input>.- money-input — Locale-aware currency input wrapping
@suaveplan/react-ui's<Input>.
- money-input — Locale-aware currency input wrapping
- async-search — Async-prefilled form recipe. Resolves an entity by
idvia the suppliedload(id, signal)callback, then mounts the u…- async-search — Async-prefilled form recipe. Resolves an entity by
idvia the suppliedload(id, signal)callback, then mounts the u…
- async-search — Async-prefilled form recipe. Resolves an entity by
- conditional — Show / hide form fields based on a predicate over the parent form's values. When the gate flips closed the recipe unreg…
- conditional — Show / hide form fields based on a predicate over the parent form's values. When the gate flips closed the recipe unreg…
- repeating-fieldset — Dynamic-array fieldset recipe backed by react-hook-form's
useFieldArray. Renders one row per array entry; add / remov…- repeating-fieldset — Dynamic-array fieldset recipe backed by react-hook-form's
useFieldArray. Renders one row per array entry; add / remov…
- repeating-fieldset — Dynamic-array fieldset recipe backed by react-hook-form's
- wizard — Multi-step wizard recipe. Each step owns a Zod sub-schema and a typed field-config map; navigating forward validates th…
- wizard — Multi-step wizard recipe. Each step owns a Zod sub-schema and a typed field-config map; navigating forward validates th…
- async-email-unique — (no submodules)
- async-email-unique — (no submodules)
- async-username-available — (no submodules)
- async-username-available — (no submodules)
- compose — (no submodules) - or — OR-semantics composer for the validator suite.…
- compose — (no submodules) - or — OR-semantics composer for the validator suite.…
- or — OR-semantics composer for the validator suite. Returns a validator that passes when any of the input validators passes.…
- sequence — Short-circuit AND composer with explicit ordering semantics. Identical to
composein result — every validator must pa… - shared — Tiny internal helper module shared by every composer in
validation/compose. Centralises thePromisediscrimination…
- bic — (no submodules)
- bic — (no submodules)
- credit-card — (no submodules)
- credit-card — (no submodules)
- custom — (no submodules)
- custom — (no submodules)
- email — (no submodules)
- email — (no submodules)
- iban — (no submodules)
- iban — (no submodules)
- max-length — (no submodules)
- max-length — (no submodules)
- min-length — (no submodules)
- min-length — (no submodules)
- password-strength — (no submodules)
- password-strength — (no submodules)
- pattern — (no submodules)
- pattern — (no submodules)
- phone — (no submodules)
- phone — (no submodules)
- postcode — (no submodules)
- postcode — (no submodules)
- required — (no submodules)
- required — (no submodules)
- url — (no submodules)
- url — (no submodules)
-
api-client-context — (no submodules)- use-api-client — React hook that reads the active `…
-
use-api-client — React hook that reads the active
ApiClientfrom the surrounding<ApiClientProvider>and returns it typed as the con… -
auth-context — (no submodules)- use-auth — React hook that reads the active `AuthCo…
- auth-context — (no submodules)- use-auth — React hook that reads the active `AuthCo…
- use-auth — React hook that reads the active
AuthContextValuefrom the surrounding<AuthProvider>and returns it typed as `Auth…
-
use-domain-form — (no submodules)- use-domain-form — (no submodules)- use-form-validation — (no submodules)- use-form-validation — (no submodules)- validation-engine — (no submodules)- cross-field-rule — Convenience factory + helper for declaring
CrossFieldRulevalues. Cross-field rules are the second pipeline phase ins…- server-error-mapper — Bridges server-side validation envelopes into the engine's per-field
ValidatorFailureshape. When a form's `submit.on… - validation-engine — (no submodules)- error-codes — Registers the thirteen stable error codes used by
@suaveplan/react-formsunder theREACT_FORMSnamespace via `defin…
- server-error-mapper — Bridges server-side validation envelopes into the engine's per-field
-
react-forms-error — Defines the base
ReactFormsErrorclass shared by every error path in@suaveplan/react-forms. Extending the project… -
create-domain-form — Declarative typed-form factory. Wraps
useDomainForm+<RHF FormProvider>+ the layout dispatcher into a single comp…- create-domain-form — Declarative typed-form factory. Wraps
useDomainForm+<RHF FormProvider>+ the layout dispatcher into a single comp…
- create-domain-form — Declarative typed-form factory. Wraps
-
field-config —
FieldConfigdiscriminated union, per-kind Zod schemas, and thevalidateFieldConfig/validateFieldConfigMaphelpe…- field-config —
FieldConfigdiscriminated union, per-kind Zod schemas, and thevalidateFieldConfig/validateFieldConfigMaphelpe…
- field-config —
-
render-field — Single-field renderer used by
useDomainFormandcreateDomainFormto turn a typedFieldConfiginto a<Field>cha…- render-field — Single-field renderer used by
useDomainFormandcreateDomainFormto turn a typedFieldConfiginto a<Field>cha…
- render-field — Single-field renderer used by
-
locales — Bundled translation strings shipped with
@suaveplan/react-forms.- augmentation — Side-effect-only TypeScript module that augments
@suaveplan/react-i18n'sContributedTranslationKeysinterface with… - locales — Bundled translation strings shipped with
@suaveplan/react-forms. - translation-keys —
translation-keys.tsis the codegen-emitted string-literal union of every translation key contributed by `@suaveplan/r…
- augmentation — Side-effect-only TypeScript module that augments
-
observability — (no submodules)- react-forms-metrics — (no submodules)- field — (no submodules)- field — (no submodules)- money-input — Locale-aware currency input wrapping
@suaveplan/react-ui's<Input>.- money-input — Locale-aware currency input wrapping
@suaveplan/react-ui's<Input>.
- money-input — Locale-aware currency input wrapping
-
async-search — Async-prefilled form recipe. Resolves an entity by
idvia the suppliedload(id, signal)callback, then mounts the u…- async-search — Async-prefilled form recipe. Resolves an entity by
idvia the suppliedload(id, signal)callback, then mounts the u…
- async-search — Async-prefilled form recipe. Resolves an entity by
-
conditional — Show / hide form fields based on a predicate over the parent form's values. When the gate flips closed the recipe unreg…
- conditional — Show / hide form fields based on a predicate over the parent form's values. When the gate flips closed the recipe unreg…
-
repeating-fieldset — Dynamic-array fieldset recipe backed by react-hook-form's
useFieldArray. Renders one row per array entry; add / remov…- repeating-fieldset — Dynamic-array fieldset recipe backed by react-hook-form's
useFieldArray. Renders one row per array entry; add / remov…
- repeating-fieldset — Dynamic-array fieldset recipe backed by react-hook-form's
-
wizard — Multi-step wizard recipe. Each step owns a Zod sub-schema and a typed field-config map; navigating forward validates th…
- wizard — Multi-step wizard recipe. Each step owns a Zod sub-schema and a typed field-config map; navigating forward validates th…
-
async-email-unique — (no submodules)- async-email-unique — (no submodules)- async-username-available — (no submodules)- async-username-available — (no submodules)- compose — (no submodules)- or — OR-semantics composer for the validator suite.…
- compose — (no submodules)- or — OR-semantics composer for the validator suite.…
- or — OR-semantics composer for the validator suite. Returns a validator that passes when any of the input validators passes.…
- sequence — Short-circuit AND composer with explicit ordering semantics. Identical to
composein result — every validator must pa… - shared — Tiny internal helper module shared by every composer in
validation/compose. Centralises thePromisediscrimination…
-
bic — (no submodules)- bic — (no submodules)- credit-card — (no submodules)- credit-card — (no submodules)- custom — (no submodules)- custom — (no submodules)- email — (no submodules)- email — (no submodules)- iban — (no submodules)- iban — (no submodules)- max-length — (no submodules)- max-length — (no submodules)- min-length — (no submodules)- min-length — (no submodules)- password-strength — (no submodules)- password-strength — (no submodules)- pattern — (no submodules)- pattern — (no submodules)- phone — (no submodules)- phone — (no submodules)- postcode — (no submodules)- postcode — (no submodules)- required — (no submodules)- required — (no submodules)- url — (no submodules)- url — (no submodules)- use-api-client — React hook that reads the active `…
-
api-client-context — (no submodules)- use-api-client — React hook that reads the active `…
-
use-api-client — React hook that reads the active
ApiClientfrom the surrounding<ApiClientProvider>and returns it typed as the con… -
auth-context — (no submodules)- use-auth — React hook that reads the active `AuthCo…
- auth-context — (no submodules)- use-auth — React hook that reads the active `AuthCo…
- use-auth — React hook that reads the active
AuthContextValuefrom the surrounding<AuthProvider>and returns it typed as `Auth…
-
use-domain-form — (no submodules)- use-domain-form — (no submodules)- use-form-validation — (no submodules)- use-form-validation — (no submodules)- validation-engine — (no submodules)- cross-field-rule — Convenience factory + helper for declaring
CrossFieldRulevalues. Cross-field rules are the second pipeline phase ins…- server-error-mapper — Bridges server-side validation envelopes into the engine's per-field
ValidatorFailureshape. When a form's `submit.on… - validation-engine — (no submodules)- error-codes — Registers the thirteen stable error codes used by
@suaveplan/react-formsunder theREACT_FORMSnamespace via `defin…
- server-error-mapper — Bridges server-side validation envelopes into the engine's per-field
-
react-forms-error — Defines the base
ReactFormsErrorclass shared by every error path in@suaveplan/react-forms. Extending the project… -
create-domain-form — Declarative typed-form factory. Wraps
useDomainForm+<RHF FormProvider>+ the layout dispatcher into a single comp…- create-domain-form — Declarative typed-form factory. Wraps
useDomainForm+<RHF FormProvider>+ the layout dispatcher into a single comp…
- create-domain-form — Declarative typed-form factory. Wraps
-
field-config —
FieldConfigdiscriminated union, per-kind Zod schemas, and thevalidateFieldConfig/validateFieldConfigMaphelpe…- field-config —
FieldConfigdiscriminated union, per-kind Zod schemas, and thevalidateFieldConfig/validateFieldConfigMaphelpe…
- field-config —
-
render-field — Single-field renderer used by
useDomainFormandcreateDomainFormto turn a typedFieldConfiginto a<Field>cha…- render-field — Single-field renderer used by
useDomainFormandcreateDomainFormto turn a typedFieldConfiginto a<Field>cha…
- render-field — Single-field renderer used by
-
locales — Bundled translation strings shipped with
@suaveplan/react-forms.- augmentation — Side-effect-only TypeScript module that augments
@suaveplan/react-i18n'sContributedTranslationKeysinterface with… - locales — Bundled translation strings shipped with
@suaveplan/react-forms. - translation-keys —
translation-keys.tsis the codegen-emitted string-literal union of every translation key contributed by `@suaveplan/r…
- augmentation — Side-effect-only TypeScript module that augments
-
observability — (no submodules)- react-forms-metrics — (no submodules)- field — (no submodules)- field — (no submodules)- money-input — Locale-aware currency input wrapping
@suaveplan/react-ui's<Input>.- money-input — Locale-aware currency input wrapping
@suaveplan/react-ui's<Input>.
- money-input — Locale-aware currency input wrapping
-
async-search — Async-prefilled form recipe. Resolves an entity by
idvia the suppliedload(id, signal)callback, then mounts the u…- async-search — Async-prefilled form recipe. Resolves an entity by
idvia the suppliedload(id, signal)callback, then mounts the u…
- async-search — Async-prefilled form recipe. Resolves an entity by
-
conditional — Show / hide form fields based on a predicate over the parent form's values. When the gate flips closed the recipe unreg…
- conditional — Show / hide form fields based on a predicate over the parent form's values. When the gate flips closed the recipe unreg…
-
repeating-fieldset — Dynamic-array fieldset recipe backed by react-hook-form's
useFieldArray. Renders one row per array entry; add / remov…- repeating-fieldset — Dynamic-array fieldset recipe backed by react-hook-form's
useFieldArray. Renders one row per array entry; add / remov…
- repeating-fieldset — Dynamic-array fieldset recipe backed by react-hook-form's
-
wizard — Multi-step wizard recipe. Each step owns a Zod sub-schema and a typed field-config map; navigating forward validates th…
- wizard — Multi-step wizard recipe. Each step owns a Zod sub-schema and a typed field-config map; navigating forward validates th…
-
async-email-unique — (no submodules)- async-email-unique — (no submodules)- async-username-available — (no submodules)- async-username-available — (no submodules)- compose — (no submodules)- or — OR-semantics composer for the validator suite.…
- compose — (no submodules)- or — OR-semantics composer for the validator suite.…
- or — OR-semantics composer for the validator suite. Returns a validator that passes when any of the input validators passes.…
- sequence — Short-circuit AND composer with explicit ordering semantics. Identical to
composein result — every validator must pa… - shared — Tiny internal helper module shared by every composer in
validation/compose. Centralises thePromisediscrimination…
-
bic — (no submodules)- bic — (no submodules)- credit-card — (no submodules)- credit-card — (no submodules)- custom — (no submodules)- custom — (no submodules)- email — (no submodules)- email — (no submodules)- iban — (no submodules)- iban — (no submodules)- max-length — (no submodules)- max-length — (no submodules)- min-length — (no submodules)- min-length — (no submodules)- password-strength — (no submodules)- password-strength — (no submodules)- pattern — (no submodules)- pattern — (no submodules)- phone — (no submodules)- phone — (no submodules)- postcode — (no submodules)- postcode — (no submodules)- required — (no submodules)- required — (no submodules)- url — (no submodules)- url — (no submodules)- use-api-client — React hook that reads the active `…
-
api-client-context — (no submodules)- use-api-client — React hook that reads the active `…
-
use-api-client — React hook that reads the active
ApiClientfrom the surrounding<ApiClientProvider>and returns it typed as the con… -
auth-context — (no submodules)- use-auth — React hook that reads the active `AuthCo…
- auth-context — (no submodules)- use-auth — React hook that reads the active `AuthCo…
- use-auth — React hook that reads the active
AuthContextValuefrom the surrounding<AuthProvider>and returns it typed as `Auth…
-
use-domain-form — (no submodules)- use-domain-form — (no submodules)- use-form-validation — (no submodules)- use-form-validation — (no submodules)- validation-engine — (no submodules)- cross-field-rule — Convenience factory + helper for declaring
CrossFieldRulevalues. Cross-field rules are the second pipeline phase ins…- server-error-mapper — Bridges server-side validation envelopes into the engine's per-field
ValidatorFailureshape. When a form's `submit.on… - validation-engine — (no submodules)- error-codes — Registers the thirteen stable error codes used by
@suaveplan/react-formsunder theREACT_FORMSnamespace via `defin…
- server-error-mapper — Bridges server-side validation envelopes into the engine's per-field
-
react-forms-error — Defines the base
ReactFormsErrorclass shared by every error path in@suaveplan/react-forms. Extending the project… -
create-domain-form — Declarative typed-form factory. Wraps
useDomainForm+<RHF FormProvider>+ the layout dispatcher into a single comp…- create-domain-form — Declarative typed-form factory. Wraps
useDomainForm+<RHF FormProvider>+ the layout dispatcher into a single comp…
- create-domain-form — Declarative typed-form factory. Wraps
-
field-config —
FieldConfigdiscriminated union, per-kind Zod schemas, and thevalidateFieldConfig/validateFieldConfigMaphelpe…- field-config —
FieldConfigdiscriminated union, per-kind Zod schemas, and thevalidateFieldConfig/validateFieldConfigMaphelpe…
- field-config —
-
render-field — Single-field renderer used by
useDomainFormandcreateDomainFormto turn a typedFieldConfiginto a<Field>cha…- render-field — Single-field renderer used by
useDomainFormandcreateDomainFormto turn a typedFieldConfiginto a<Field>cha…
- render-field — Single-field renderer used by
-
locales — Bundled translation strings shipped with
@suaveplan/react-forms.- augmentation — Side-effect-only TypeScript module that augments
@suaveplan/react-i18n'sContributedTranslationKeysinterface with… - locales — Bundled translation strings shipped with
@suaveplan/react-forms. - translation-keys —
translation-keys.tsis the codegen-emitted string-literal union of every translation key contributed by `@suaveplan/r…
- augmentation — Side-effect-only TypeScript module that augments
-
observability — (no submodules)- react-forms-metrics — (no submodules)- field — (no submodules)- field — (no submodules)- money-input — Locale-aware currency input wrapping
@suaveplan/react-ui's<Input>.- money-input — Locale-aware currency input wrapping
@suaveplan/react-ui's<Input>.
- money-input — Locale-aware currency input wrapping
-
async-search — Async-prefilled form recipe. Resolves an entity by
idvia the suppliedload(id, signal)callback, then mounts the u…- async-search — Async-prefilled form recipe. Resolves an entity by
idvia the suppliedload(id, signal)callback, then mounts the u…
- async-search — Async-prefilled form recipe. Resolves an entity by
-
conditional — Show / hide form fields based on a predicate over the parent form's values. When the gate flips closed the recipe unreg…
- conditional — Show / hide form fields based on a predicate over the parent form's values. When the gate flips closed the recipe unreg…
-
repeating-fieldset — Dynamic-array fieldset recipe backed by react-hook-form's
useFieldArray. Renders one row per array entry; add / remov…- repeating-fieldset — Dynamic-array fieldset recipe backed by react-hook-form's
useFieldArray. Renders one row per array entry; add / remov…
- repeating-fieldset — Dynamic-array fieldset recipe backed by react-hook-form's
-
wizard — Multi-step wizard recipe. Each step owns a Zod sub-schema and a typed field-config map; navigating forward validates th…
- wizard — Multi-step wizard recipe. Each step owns a Zod sub-schema and a typed field-config map; navigating forward validates th…
-
async-email-unique — (no submodules)- async-email-unique — (no submodules)- async-username-available — (no submodules)- async-username-available — (no submodules)- compose — (no submodules)- or — OR-semantics composer for the validator suite.…
- compose — (no submodules)- or — OR-semantics composer for the validator suite.…
- or — OR-semantics composer for the validator suite. Returns a validator that passes when any of the input validators passes.…
- sequence — Short-circuit AND composer with explicit ordering semantics. Identical to
composein result — every validator must pa… - shared — Tiny internal helper module shared by every composer in
validation/compose. Centralises thePromisediscrimination…
-
bic — (no submodules)- bic — (no submodules)- credit-card — (no submodules)- credit-card — (no submodules)- custom — (no submodules)- custom — (no submodules)- email — (no submodules)- email — (no submodules)- iban — (no submodules)- iban — (no submodules)- max-length — (no submodules)- max-length — (no submodules)- min-length — (no submodules)- min-length — (no submodules)- password-strength — (no submodules)- password-strength — (no submodules)- pattern — (no submodules)- pattern — (no submodules)- phone — (no submodules)- phone — (no submodules)- postcode — (no submodules)- postcode — (no submodules)- required — (no submodules)- required — (no submodules)- url — (no submodules)- url — (no submodules)- api-client-context — (no submodules)- use-api-client — React hook that reads the active
ApiClientfrom the surrounding<ApiClientProvider>and returns it typed as the con… -
auth-context — (no submodules) - auth-context — (no submodules) - use-auth — React hook that reads the active
AuthContextValuefrom the surrounding<AuthProvider>and returns it typed as `Auth… -
use-domain-form — (no submodules) - use-domain-form — (no submodules)- use-form-validation — (no submodules) - use-form-validation — (no submodules)- validation-engine — (no submodules) - cross-field-rule — Convenience factory + helper for declaring
CrossFieldRulevalues. Cross-field rules are the second pipeline phase ins…- server-error-mapper — Bridges server-side validation envelopes into the engine's per-field
ValidatorFailureshape. When a form's `submit.on… - validation-engine — (no submodules)- error-codes — Registers the thirteen stable error codes used by
@suaveplan/react-formsunder theREACT_FORMSnamespace via `defin…
- server-error-mapper — Bridges server-side validation envelopes into the engine's per-field
-
react-forms-error — Defines the base
ReactFormsErrorclass shared by every error path in@suaveplan/react-forms. Extending the project… -
create-domain-form — Declarative typed-form factory. Wraps
useDomainForm+<RHF FormProvider>+ the layout dispatcher into a single comp…- create-domain-form — Declarative typed-form factory. Wraps
useDomainForm+<RHF FormProvider>+ the layout dispatcher into a single comp…
- create-domain-form — Declarative typed-form factory. Wraps
-
field-config —
FieldConfigdiscriminated union, per-kind Zod schemas, and thevalidateFieldConfig/validateFieldConfigMaphelpe…- field-config —
FieldConfigdiscriminated union, per-kind Zod schemas, and thevalidateFieldConfig/validateFieldConfigMaphelpe…
- field-config —
-
render-field — Single-field renderer used by
useDomainFormandcreateDomainFormto turn a typedFieldConfiginto a<Field>cha…- render-field — Single-field renderer used by
useDomainFormandcreateDomainFormto turn a typedFieldConfiginto a<Field>cha…
- render-field — Single-field renderer used by
-
locales — Bundled translation strings shipped with
@suaveplan/react-forms.- augmentation — Side-effect-only TypeScript module that augments
@suaveplan/react-i18n'sContributedTranslationKeysinterface with… - locales — Bundled translation strings shipped with
@suaveplan/react-forms. - translation-keys —
translation-keys.tsis the codegen-emitted string-literal union of every translation key contributed by `@suaveplan/r…
- augmentation — Side-effect-only TypeScript module that augments
-
observability — (no submodules) - react-forms-metrics — (no submodules)- field — (no submodules) - field — (no submodules)- money-input — Locale-aware currency input wrapping
@suaveplan/react-ui's<Input>.- money-input — Locale-aware currency input wrapping
@suaveplan/react-ui's<Input>.
- money-input — Locale-aware currency input wrapping
-
async-search — Async-prefilled form recipe. Resolves an entity by
idvia the suppliedload(id, signal)callback, then mounts the u…- async-search — Async-prefilled form recipe. Resolves an entity by
idvia the suppliedload(id, signal)callback, then mounts the u…
- async-search — Async-prefilled form recipe. Resolves an entity by
-
conditional — Show / hide form fields based on a predicate over the parent form's values. When the gate flips closed the recipe unreg…
- conditional — Show / hide form fields based on a predicate over the parent form's values. When the gate flips closed the recipe unreg…
-
repeating-fieldset — Dynamic-array fieldset recipe backed by react-hook-form's
useFieldArray. Renders one row per array entry; add / remov…- repeating-fieldset — Dynamic-array fieldset recipe backed by react-hook-form's
useFieldArray. Renders one row per array entry; add / remov…
- repeating-fieldset — Dynamic-array fieldset recipe backed by react-hook-form's
-
wizard — Multi-step wizard recipe. Each step owns a Zod sub-schema and a typed field-config map; navigating forward validates th…
- wizard — Multi-step wizard recipe. Each step owns a Zod sub-schema and a typed field-config map; navigating forward validates th…
-
async-email-unique — (no submodules) - async-email-unique — (no submodules)- async-username-available — (no submodules) - async-username-available — (no submodules)- compose — (no submodules) - compose — (no submodules) - or — OR-semantics composer for the validator suite. Returns a validator that passes when any of the input validators passes.…
-
bic — (no submodules) - bic — (no submodules)- credit-card — (no submodules) - credit-card — (no submodules)- custom — (no submodules) - custom — (no submodules)- email — (no submodules) - email — (no submodules)- iban — (no submodules) - iban — (no submodules)- max-length — (no submodules) - max-length — (no submodules)- min-length — (no submodules) - min-length — (no submodules)- password-strength — (no submodules) - password-strength — (no submodules)- pattern — (no submodules) - pattern — (no submodules)- phone — (no submodules) - phone — (no submodules)- postcode — (no submodules) - postcode — (no submodules)- required — (no submodules) - required — (no submodules)- url — (no submodules) - url — (no submodules)
Install
bun add @suaveplan/react-forms
Peer deps: react ^18.0.0 || ^19.0.0, @suaveplan/react-ui (must be
provided by the consumer; this package re-exports <Field> and
imports <Input> / <Button> / <Skeleton> / etc. from it).
Workspace deps: @suaveplan/react-i18n (TranslationKey),
@suaveplan/react-ui (component primitives), @suaveplan/error
(ReactFormsError), @suaveplan/timing (async-validator debounce),
@suaveplan/api-schemas, @suaveplan/i18n (currency / date
formatters).
External catalog deps: react-hook-form, @hookform/resolvers,
zod, libphonenumber-js, @zxcvbn-ts/core, @opentelemetry/api.
Quick start — createDomainForm
The factory is the 80%-case ergonomics layer. Declare a Zod schema + field config + submit handler:
import { createDomainForm } from "@suaveplan/react-forms";
import { RegisterInput } from "@suaveplan/api-schemas";
const RegisterForm = createDomainForm({
formId: "register",
schema: RegisterInput,
fields: {
email: { kind: "email", label: "auth.email.label" as never },
password: {
kind: "password",
label: "auth.password.label" as never,
strengthMeter: true,
},
name: { kind: "text", label: "auth.name.label" as never },
},
defaultValues: { email: "", password: "", name: "" },
submit: {
label: "auth.register.submit" as never,
onSubmit: async (values) => {
await fetch("/api/auth/register", {
method: "POST",
body: JSON.stringify(values),
});
},
},
});
export function RegisterPage(): JSX.Element {
return <RegisterForm />;
}
Three escape hatches keep RHF visible:
// 1. Render-prop children for full custom shells:
<RegisterForm>
{({ form, fields, submit, isSubmitting }) => (
<CustomLayout>{Object.values(fields)}</CustomLayout>
)}
</RegisterForm>
// 2. Static <Form.Field name=...> for partial layouts:
<div>
<RegisterForm.Field name="email" />
<p>Then choose a password.</p>
<RegisterForm.Field name="password" />
</div>
// 3. The standalone useDomainForm hook, exported separately:
const { form, fields, submit } = useDomainForm({ ...config });
Recipes
Wizard — multi-step factory
import { createWizardForm } from "@suaveplan/react-forms";
const SignUpWizard = createWizardForm({
formId: "signup",
steps: [
{
id: "credentials",
title: "auth.steps.credentials" as never,
schema: z.object({ email: z.string().email(), password: z.string().min(8) }),
fields: {
email: { kind: "email", label: "auth.email.label" as never },
password: { kind: "password", label: "auth.password.label" as never },
},
},
{
id: "profile",
title: "auth.steps.profile" as never,
schema: z.object({ name: z.string().min(1) }),
fields: {
name: { kind: "text", label: "auth.name.label" as never },
},
},
],
onComplete: async (values) => api.auth.register(values),
});
Repeating fieldset — dynamic-array rows
import { createRepeatingFieldset } from "@suaveplan/react-forms";
const Contacts = createRepeatingFieldset<{ name: string; email: string }>({
formId: "checkout",
name: "contacts",
minRows: 1,
maxRows: 5,
defaultRow: { name: "", email: "" },
fieldset: {
name: { kind: "text", label: "checkout.contact.name" as never },
email: { kind: "email", label: "checkout.contact.email" as never },
},
});
Conditional — show/hide fields
import { ConditionalField } from "@suaveplan/react-forms";
<ConditionalField<CheckoutValues>
when={(v) => v.paymentMethod === "transfer"}
names={["bankAccount"]}
watch={["paymentMethod"]}
>
<RegisterForm.Field name="bankAccount" />
</ConditionalField>
When the gate flips closed the recipe unregisters bankAccount
from the form so it disappears from the submit payload.
Async search — load-then-edit
import { createAsyncSearchForm } from "@suaveplan/react-forms";
const EditUserForm = createAsyncSearchForm({
formId: "edit-user",
schema,
fields: {
email: { kind: "email", label: "user.email.label" as never },
name: { kind: "text", label: "user.name.label" as never },
},
load: async (id, signal) => {
const res = await fetch(`/api/users/${id}`, { signal });
return (await res.json()) as { email: string; name: string };
},
submit: {
label: "user.save" as never,
onSubmit: async (values) => {
await fetch(`/api/users/${id}`, {
method: "PUT",
body: JSON.stringify(values),
});
},
},
});
<EditUserForm id="alice" />;
Validation library — sync + async + composers
import {
compose,
email,
minLength,
passwordStrength,
required,
sequence,
} from "@suaveplan/react-forms";
const validateEmail = sequence(required(), email());
const validatePassword = compose(
required(),
minLength(8),
passwordStrength({ minScore: 3 })
);
validateEmail("alice@example.com"); // → { valid: true }
validatePassword("hunter2"); // → { valid: false, messageKey, messageArgs }
Async validators receive an AbortSignal:
import { asyncEmailUnique } from "@suaveplan/react-forms";
const checkEmailUnique = asyncEmailUnique({
check: async (email, signal) => {
const res = await fetch(
`/api/users/email-available?email=${encodeURIComponent(email)}`,
{ signal }
);
return res.ok;
},
debounceMs: 300,
});
Standalone hooks
useDomainForm is exported separately for consumers building bespoke
shells:
import { useDomainForm } from "@suaveplan/react-forms";
const { form, fields, submit, isSubmitting, serverError } = useDomainForm({
formId: "login",
schema,
fields, // optional — when omitted, `fields` is null
onSubmit: async (values) => api.auth.login(values),
});
Field kinds shipped in Wave 5b
text, email, password (with optional strengthMeter),
number, currency (uses MoneyInput), checkbox, toggle,
radio, textarea, custom (consumer render-prop).
Deferred primitives — Wave 5c roadmap
The following primitives and field kinds are NOT in Wave 5b. They ship in Wave 5c once the underlying react-ui components land:
| Primitive | Underlying component | Wave |
|---|---|---|
accessible-date-picker |
Calendar (react-ui) |
Wave 5c after react-ui Wave 3h |
date-time-picker |
Calendar + TimeInput |
Wave 5c after react-ui Wave 3h |
searchable-select |
Combobox (react-ui) |
Wave 5c after react-ui Wave 3h |
tag-input |
Badge (react-ui) |
Wave 5c after react-ui Wave 3d |
code-input |
InputOTP (react-ui) |
Wave 5c after react-ui Wave 3h |
file-upload-field |
@suaveplan/react-file-upload |
Wave 5c after react-file-upload ships |
rich-text-field |
@suaveplan/react-rich-text |
Wave 5c after react-rich-text ships |
Field kinds excluded from the Wave 5b enum: date, dateTime,
select, multi-select, combobox, file, rich-text, otp.
Passing one of these to createDomainForm today fails the
discriminator and throws REACT_FORMS.FIELD_KIND_INVALID at
module-eval time.
Modules
src/errors/error-codes.md— REACT_FORMS error code registry.src/errors/react-forms-error.md—ReactFormsErrorbase class.src/observability/react-forms-metrics.md— OTel instruments and in-memory ring.src/locales/locales.md— bundled recipe-default strings.src/locales/translation-keys.md— codegen union of contributed keys.src/locales/augmentation.md—ContributedTranslationKeysregistration.src/core/api-client-context/api-client-context.md—<ApiClientProvider>+useApiClient.src/core/api-client-context/use-api-client.md— hook details + throw semantics.src/core/auth-context/auth-context.md—<AuthProvider>+useAuth.src/core/auth-context/use-auth.md— hook details + throw semantics.src/core/validation-engine/validation-engine.md— four-phase pipeline.src/core/validation-engine/cross-field-rule.md—defineCrossFieldRule+violate.src/core/validation-engine/server-error-mapper.md— server envelope unwrap + map.src/core/use-form-validation/use-form-validation.md— RHF resolver bridge.src/core/use-domain-form/use-domain-form.md— standalone domain-form hook (now with field rendering).src/primitives/field/field.md— single-source re-export of react-ui's Field family.src/primitives/money-input/money-input.md— locale-aware currency input.src/factory/field-config/field-config.md— discriminated-union FieldConfig + Zod schemas.src/factory/render-field/render-field.md— single-field renderer.src/factory/create-domain-form/create-domain-form.md— declarative factory + escape hatches.src/recipes/wizard/wizard.md— multi-step factory.src/recipes/repeating-fieldset/repeating-fieldset.md— dynamic-array fieldset.src/recipes/conditional/conditional.md— show/hide field gate.src/recipes/async-search/async-search.md— load-then-edit recipe.src/validation/validators/required/required.md— presence validator.src/validation/validators/min-length/min-length.md— minimum length.src/validation/validators/max-length/max-length.md— maximum length.src/validation/validators/email/email.md— RFC 5322 subset email.src/validation/validators/url/url.md— WHATWG URL.src/validation/validators/pattern/pattern.md— regex match.src/validation/validators/phone/phone.md— libphonenumber-js phone.src/validation/validators/postcode/postcode.md— per-country postcode.src/validation/validators/credit-card/credit-card.md— Luhn checksum.src/validation/validators/password-strength/password-strength.md— zxcvbn-backed strength.src/validation/validators/iban/iban.md— ISO 13616 IBAN.src/validation/validators/bic/bic.md— ISO 9362 BIC.src/validation/validators/custom/custom.md— predicate adapter.src/validation/async/async-email-unique/async-email-unique.md— debounced email-uniqueness.src/validation/async/async-username-available/async-username-available.md— debounced username-availability.src/validation/compose/compose.md— AND composer.src/validation/compose/or.md— OR composer.src/validation/compose/sequence.md— ordered AND composer.