Skip to content

Validation

Use a Standard Schema-compatible schema when you want one source of truth for validation and submit value types. Schema issues with field paths are mapped back onto registered fields on submit.

import { z } from 'zod';
import { Form, InputField, PasswordField, SubmitButton } from '@gxxc/solid-forms';
const loginSchema = z.object({
email: z.string().email('Enter a valid email'),
password: z.string().min(8, 'Password must be at least 8 characters')
});
<Form
schema={loginSchema}
onSubmit={(values) => {
values.email; // string
values.password; // string
}}
>
<InputField name='email' label='Email' />
<PasswordField name='password' label='Password' />
<SubmitButton>Log in</SubmitButton>
</Form>;

Use useForm({ schema }) for the same inference when you need state outside the form tree.

Field-level constraints are still available as field props. Errors appear after the user has blurred a field or submitted the form.

<InputField
name='username'
label='Username'
required
minLength={3}
maxLength={20}
pattern={/^[a-z0-9_]+$/}
/>
<InputField name='age' label='Age' min={18} max={120} />
<InputField name='confirm' label='Confirm password' match='password' />
Constraint Type Description
required boolean Field must have a non-empty value
minLength number Minimum string length
maxLength number Maximum string length
min number Minimum numeric value, parsed with the field parse prop
max number Maximum numeric value, parsed with the field parse prop
pattern string | RegExp Value must match the pattern
match string Value must equal the named field’s current value

Set a constraint prop to false to disable that constraint entirely, for example required={false}.

Use a validator function for logic that built-in constraints cannot express. Custom validators run only when no built-in errors exist on the field.

<InputField
name='username'
label='Username'
validator={async (name, value, formState, setErrors) => {
const taken = await api.checkUsername(value as string);
if (taken) {
setErrors(['Username is already taken']);
}
}}
/>

The validator signature is:

type CustomValidator<M, N extends keyof M> = (
fieldName: N,
fieldValue: M[N],
formState: FormState<M>,
setFieldErrors: (errors: string[]) => void
) => void | Promise<void>;

Sync validators call setErrors before returning. Async validators call setErrors when the promise resolves.