Testing TanStack Form field-level validation with @cleverbrush/schema via the Standard Schema v1 interface.
TanStack Form accepts any Standard Schema v1 compliant validator in its validators prop. Every @cleverbrush/schema builder exposes a ["~standard"] property that implements the spec, so you can pass schemas directly — no adapter needed.
import { useForm } from '@tanstack/react-form';
import { string, number } from '@cleverbrush/schema';
const nameSchema = string()
.required('Name is required')
.minLength(2, 'Name must be at least 2 characters');
const ageSchema = number()
.required('Age is required')
.min(18, 'Must be at least 18 years old');
function MyForm() {
const form = useForm({
defaultValues: { name: '', age: undefined },
onSubmit: async ({ value }) => console.log(value),
});
return (
<form onSubmit={e => { e.preventDefault(); form.handleSubmit(); }}>
<form.Field
name="name"
validators={{ onChange: nameSchema, onBlur: nameSchema }}
>
{field => (
<>
<input
value={field.state.value}
onChange={e => field.handleChange(e.target.value)}
onBlur={field.handleBlur}
/>
{field.state.meta.errors.map(err => (
<span key={String(err)}>{String(err)}</span>
))}
</>
)}
</form.Field>
<button type="submit">Submit</button>
</form>
);
}Each field uses a @cleverbrush/schema validator passed directly as a Standard Schema. Errors appear on change after the first interaction, and again on blur.
The schemas used in the form above — each is a fully Standard Schema v1 compliant object (inspect nameSchema["~standard"] in the console to verify):
import { string, number, boolean, object } from '@cleverbrush/schema';
const nameSchema = string()
.required('Name is required')
.minLength(2, 'Name must be at least 2 characters')
.maxLength(80, 'Name must be at most 80 characters');
const emailSchema = string()
.required('Email is required')
.matches(/^[^\s@]+@[^\s@]+\.[^\s@]+$/, 'Please enter a valid email address');
const ageSchema = number()
.required('Age is required')
.min(18, 'Must be at least 18 years old')
.max(120, 'Must be at most 120');
const bioSchema = string()
.maxLength(300, 'Bio must be at most 300 characters');
// Standard Schema interface:
// nameSchema['~standard'].version // => 1
// nameSchema['~standard'].vendor // => '@cleverbrush/schema'
// nameSchema['~standard'].validate('Hi')
// => { issues: [{ message: 'Name must be at least 2 characters' }] }