Build a real account-creation form with typed fields, conditional company fields, inline validation, and the same schema on web and native.
- One schema defines labels, rules, defaults, and platform hints
useFormBridge()gives you the wrapper, generated fields, submit lifecycle, and reactive state- Conditional company fields stay in the builder instead of leaking into component branches
Track state and submit lifecycle
You rarely need custom local state for the form itself. The hook already exposes the pieces most product flows care about.
state.isValid,state.isDirty, andstate.isSubmittingdrive button states and shell feedbackwatchAll()is useful for live previews or summary cardssubmit()lets you trigger the same submit pipeline from an outer button or wizard shell
SignupState.tsxtsx
| 1 | const form = useFormBridge(schema, { |
| 2 | validateOn: 'onTouched', |
| 3 | revalidateOn: 'onChange', |
| 4 | }) |
| 5 | |
| 6 | const { Form, fields, state, watchAll, submit } = form |
| 7 | const liveValues = watchAll() |
| 8 | const canContinue = state.isValid && !state.isSubmitting |
| 9 | |
| 10 | return ( |
| 11 | <> |
| 12 | <aside>{liveValues.email || 'No email yet'}</aside> |
| 13 | <Form onSubmit={async (values) => api.signup(values)}> |
| 14 | <fields.email /> |
| 15 | <fields.password /> |
| 16 | <Form.Submit disabled={!canContinue}>Create account</Form.Submit> |
| 17 | </Form> |
| 18 | <button type="button" onClick={() => void submit()}> |
| 19 | Submit from outer shell |
| 20 | </button> |
| 21 | </> |
| 22 | ) |
Progressive disclosure stays in the schema
Conditional fields are one of the first places where ad hoc forms become noisy. Keep them in the builders instead.
visibleWhen(...)controls whether the field rendersrequiredWhen(...)keeps the validation rule aligned with visibilityclearOnHide()orresetOnHide()prevents stale hidden values from leaking into submit payloads
SignupDisclosure.tsts
| 1 | const schema = { |
| 2 | accountType: field.select('Account type').options([ |
| 3 | { label: 'Personal', value: 'personal' }, |
| 4 | { label: 'Company', value: 'company' }, |
| 5 | ]).required(), |
| 6 | companyName: field |
| 7 | .text('Company name') |
| 8 | .visibleWhen('accountType', 'company') |
| 9 | .requiredWhen('accountType', 'company') |
| 10 | .clearOnHide(), |
| 11 | vatNumber: field |
| 12 | .text('VAT number') |
| 13 | .visibleWhen('accountType', 'company') |
| 14 | .requiredWhen('accountType', 'company') |
| 15 | .clearOnHide(), |
| 16 | } |