Technology handbook
Conform - Validation libraries
Progressively enhanced forms with schema validation, accessible errors and server integration.
- Topics
- 24
- Sections
- 4
Schema integration
Zod integration
Parse and validate a submission with a Zod schema on both sides.
- One Zod schema validates the submission on the server and the client.
- Issue paths map onto field names, which is what puts a message on the right input.
- Sharing the schema keeps the two sides from drifting apart silently.
Valibot and Yup
Use an alternative schema library through the matching adapter.
- An adapter lets an alternative schema library produce the same result shape.
- Only the adapter changes; the form code above it does not.
- Libraries differ on coercion and optionality, which shows up as different errors.
Shared schemas
Define the shape once and reuse it for the form and the API.
- The shape is defined once and reused by the form and the API.
- A single definition is what stops the endpoint accepting what the form rejects.
- Only the schema is shared; messages can still be written per surface.
Coercion
Convert string form values into numbers, dates and booleans safely.
- Form values arrive as strings, so numbers, dates and booleans need converting.
- An unchecked checkbox sends nothing at all rather than a false value.
- Coercing before validating is what stops a valid number failing as a string.
Conditional schemas
Require a field only when another value makes it relevant.
- A field becomes required only when another value makes it relevant.
- The condition belongs in the schema so the server enforces it too.
- A hidden field that is still required is a form nobody can submit.
Async validation
Check uniqueness against a server without blocking every keystroke.
- A uniqueness check reaches the server without running on every keystroke.
- Debouncing is what keeps one check per pause rather than one per character.
- The async result must be re-checked on submit, because it can go stale.
Server integration
Server actions
Handle a submission server-side and return a result the form can render.
- The submission is handled server-side and returns a result the form renders.
- Returning the result rather than throwing is what keeps the errors renderable.
- The action runs on the server, so it may reach the database directly.
Returning errors
Map server-side failures back onto the fields that caused them.
- A server-side failure is mapped back onto the field that caused it.
- A unique-constraint violation belongs on the field, not in a banner.
- An error with no field to attach to needs a form-level place to land.
Redirect after success
Avoid a resubmission on refresh after a successful write.
- Redirecting after a successful write stops a refresh resubmitting it.
- Post-then-redirect is what keeps the back button from replaying the write.
- Redirecting before the write commits reports success that may not have happened.
Framework adapters
Integrate with Next.js, Remix or React Router.
- An adapter connects the form to Next.js, Remix or React Router.
- Only submission and redirect handling differ; the schema does not.
- The adapter decides where the result comes from on a server render.
Security
Treat every submitted field as untrusted regardless of the client schema.
- Every submitted field is untrusted no matter what the client schema said.
- A direct post never runs the client validation at all.
- Accepting fields the schema does not name is how extra values reach the database.
Testing
Test a submission with scripting disabled as well as enabled.
- The form is tested with scripting disabled as well as enabled.
- Only the scriptless path proves the progressive enhancement actually works.
- Asserting on the rendered message catches a break the schema test cannot.
Sources
- Conform - Validation libraries official documentation