Skip to content

Commit 6a82b7f

Browse files
authored
feat: native support for standard schema libraries (#1020)
* feat: naive implementation as adapter * test: naive test with valibot * feat: add async validation support * feat: define standard schema adapter in form-core * feat: support arktype's function-based structure and path * ci: apply automated fixes and generate docs * feat: validate form with standard schema without adapter * feat: validate field with standard schema without adapter * test: add todo tests for zod * ci: apply automated fixes and generate docs * fix: spread field errors from form validator * docs: add example with multiple schemas * chore: bump valibot and uncomment failing tests * docs: mention standard schema * feat: accept functional sync validator even with an adapter set * chore: bump versions * docs: gen * ci: apply automated fixes and generate docs * feat: integrate zod * docs: update with zod and simplify examples * ci: apply automated fixes and generate docs * docs: mention latest version for schema libraries
1 parent b437abe commit 6a82b7f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+1663
-520
lines changed

docs/config.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -442,6 +442,10 @@
442442
"label": "TanStack Query Integration",
443443
"to": "framework/react/examples/query-integration"
444444
},
445+
{
446+
"label": "Standard Schema",
447+
"to": "framework/react/examples/standard-schema"
448+
},
445449
{
446450
"label": "Yup",
447451
"to": "framework/react/examples/yup"

docs/framework/angular/guides/validation.md

Lines changed: 49 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -382,24 +382,22 @@ This will debounce every async call with a 500ms delay. You can even override th
382382

383383
> This will run `onChangeAsync` every 1500ms while `onBlurAsync` will run every 500ms.
384384
385-
## Adapter-Based Validation (Zod, Yup, Valibot)
385+
## Validation through Schema Libraries
386386

387-
While functions provide more flexibility and customization over your validation, they can be a bit verbose. To help solve this, there are libraries like [Valibot](https://valibot.dev/), [Yup](https://github.com/jquense/yup), and [Zod](https://zod.dev/) that provide schema-based validation to make shorthand and type-strict validation substantially easier.
387+
While functions provide more flexibility and customization over your validation, they can be a bit verbose. To help solve this, there are libraries that provide schema-based validation to make shorthand and type-strict validation substantially easier. You can also define a single schema for your entire form and pass it to the form level, errors will be automatically propagated to the fields.
388388

389-
Luckily, we support all of these libraries through official adapters:
389+
### Standard Schema Libraries
390390

391-
```bash
392-
$ npm install @tanstack/zod-form-adapter zod
393-
# or
394-
$ npm install @tanstack/yup-form-adapter yup
395-
# or
396-
$ npm install @tanstack/valibot-form-adapter valibot
397-
```
391+
TanStack Form natively supports all libraries following the [Standard Schema specification](https://github.com/standard-schema/standard-schema), most notably:
392+
- [Zod](https://zod.dev/)
393+
- [Valibot](https://valibot.dev/)
394+
- [ArkType](https://arktype.io/)
398395

399-
Once done, we can add the adapter to the `validator` property on the form or field:
396+
*Note:* make sure to use the latest version of the schema libraries as older versions might not support Standard Schema yet.
397+
398+
To use schemas from these libraries you can pass them to the `validators` props as you would do with a custom function:
400399

401400
```angular-ts
402-
import { zodValidator } from '@tanstack/zod-form-adapter'
403401
import { z } from 'zod'
404402
405403
@Component({
@@ -420,19 +418,18 @@ import { z } from 'zod'
420418
`,
421419
})
422420
export class AppComponent {
423-
form = injectForm({
424-
// Either add the validator here or on `Field`
425-
validatorAdapter: zodValidator(),
421+
form = injectForm({
426422
// ...
427-
})
423+
})
428424
429425
z = z
430426
431427
// ...
432428
}
433429
```
434430

435-
These adapters also support async operations using the proper property names:
431+
Async validations on form and field level are supported as well:
432+
436433

437434
```angular-ts
438435
@Component({
@@ -469,37 +466,50 @@ export class AppComponent {
469466
}
470467
```
471468

472-
### Form Level Adapter Validation
469+
### Other Schema Libraries
473470

474-
You can also use the adapter at the form level:
471+
We also support [Yup](https://github.com/jquense/yup) through an official adapter:
475472

476-
```typescript
477-
import { zodValidator } from '@tanstack/zod-form-adapter'
478-
import { z } from 'zod'
473+
```bash
474+
$ npm install @tanstack/yup-form-adapter yup
475+
```
479476

480-
// ...
477+
Once done, we can add the adapter to the `validator` property on the form or field:
481478

482-
const form = injectForm({
483-
validatorAdapter: zodValidator(),
484-
validators: {
485-
onChange: z.object({
486-
age: z.number().gte(13, 'You must be 13 to make an account'),
487-
}),
488-
},
489-
})
490-
```
479+
```angular-ts
480+
import { yupValidator } from '@tanstack/yup-form-adapter'
481+
import * as yup from 'yup'
491482
492-
If you use the adapter at the form level, it will pass the validation to the fields of the same name.
483+
@Component({
484+
selector: 'app-root',
485+
standalone: true,
486+
imports: [TanStackField],
487+
template: `
488+
<ng-container
489+
[tanstackField]="form"
490+
name="age"
491+
[validators]="{
492+
onChange: yup.number().moreThan(13, 'You must be 13 to make an account'),
493+
}"
494+
#age="field"
495+
>
496+
<!-- ... -->
497+
</ng-container>
498+
`,
499+
})
500+
export class AppComponent {
501+
form = injectForm({
502+
// Either add the validator here or on `Field`
503+
validatorAdapter: yupValidator(),
504+
// ...
505+
})
493506
494-
This means that:
507+
yup = yup
495508
496-
```html
497-
<ng-container [tanstackField]="form" name="age" #age="field">
498-
<!-- ... -->
499-
</ng-container>
509+
// ...
510+
}
500511
```
501512

502-
Will still display the error message from the form-level validation.
503513

504514
## Preventing invalid forms from being submitted
505515

docs/framework/react/guides/ssr.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ This section focuses on integrating TanStack Form with TanStack Start.
2020

2121
- Start a new `TanStack Start` project, following the steps in the [TanStack Start Quickstart Guide](https://tanstack.com/router/latest/docs/framework/react/guide/tanstack-start)
2222
- Install `@tanstack/react-form`
23-
- Install any [form validator](/form/latest/docs/framework/react/guides/validation#adapter-based-validation-zod-yup-valibot) of your choice. [Optional]
23+
- Install any [form validator](/form/latest/docs/framework/react/guides/validation#validation-through-schema-libraries) of your choice. [Optional]
2424

2525
### Start integration
2626

@@ -169,7 +169,7 @@ This section focuses on integrating TanStack Form with `Next.js`, particularly u
169169

170170
- Start a new `Next.js` project, following the steps in the [Next.js Documentation](https://nextjs.org/docs/getting-started/installation). Ensure you select `yes` for `Would you like to use App Router?` during the setup to access all new features provided by Next.js.
171171
- Install `@tanstack/react-form`
172-
- Install any [form validator](/form/latest/docs/framework/react/guides/validation#adapter-based-validation-zod-yup-valibot) of your choice. [Optional]
172+
- Install any [form validator](/form/latest/docs/framework/react/guides/validation#validation-through-schema-libraries) of your choice. [Optional]
173173

174174
## App Router integration
175175

@@ -315,7 +315,7 @@ Here, we're using [React's `useActionState` hook](https://unicorn-utterances.com
315315
316316
- Start a new `Remix` project, following the steps in the [Remix Documentation](https://remix.run/docs/en/main/start/quickstart).
317317
- Install `@tanstack/react-form`
318-
- Install any [form validator](/form/latest/docs/framework/react/guides/validation#adapter-based-validation-zod-yup-valibot) of your choice. [Optional]
318+
- Install any [form validator](/form/latest/docs/framework/react/guides/validation#validation-through-schema-libraries) of your choice. [Optional]
319319
320320
## Remix integration
321321

docs/framework/react/guides/validation.md

Lines changed: 50 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -413,47 +413,49 @@ This will debounce every async call with a 500ms delay. You can even override th
413413
414414
> This will run `onChangeAsync` every 1500ms while `onBlurAsync` will run every 500ms.
415415
416-
## Adapter-Based Validation (Zod, Yup, Valibot)
416+
## Validation through Schema Libraries
417417
418-
While functions provide more flexibility and customization over your validation, they can be a bit verbose. To help solve this, there are libraries like [Valibot](https://valibot.dev/), [Yup](https://github.com/jquense/yup), and [Zod](https://zod.dev/) that provide schema-based validation to make shorthand and type-strict validation substantially easier.
418+
While functions provide more flexibility and customization over your validation, they can be a bit verbose. To help solve this, there are libraries that provide schema-based validation to make shorthand and type-strict validation substantially easier. You can also define a single schema for your entire form and pass it to the form level, errors will be automatically propagated to the fields.
419419
420-
Luckily, we support all of these libraries through official adapters:
420+
### Standard Schema Libraries
421421
422-
```bash
423-
$ npm install @tanstack/zod-form-adapter zod
424-
# or
425-
$ npm install @tanstack/yup-form-adapter yup
426-
# or
427-
$ npm install @tanstack/valibot-form-adapter valibot
428-
```
422+
TanStack Form natively supports all libraries following the [Standard Schema specification](https://github.com/standard-schema/standard-schema), most notably:
423+
- [Zod](https://zod.dev/)
424+
- [Valibot](https://valibot.dev/)
425+
- [ArkType](https://arktype.io/)
429426
430-
Once done, we can add the adapter to the `validator` property on the form or field:
427+
*Note:* make sure to use the latest version of the schema libraries as older versions might not support Standard Schema yet.
431428
432-
```tsx
433-
import { zodValidator } from '@tanstack/zod-form-adapter'
434-
import { z } from 'zod'
435-
436-
// ...
429+
To use schemas from these libraries you can pass them to the `validators` props as you would do with a custom function:
437430
438-
const form = useForm({
439-
// Either add the validator here or on `Field`
440-
validatorAdapter: zodValidator(),
441-
// ...
431+
```tsx
432+
const userSchema = z.object({
433+
age: z.number().gte(13, 'You must be 13 to make an account'),
442434
})
443435
444-
<form.Field
445-
name="age"
446-
validatorAdapter={zodValidator()}
447-
validators={{
448-
onChange: z.number().gte(13, 'You must be 13 to make an account'),
449-
}}
450-
children={(field) => {
451-
return <>{/* ... */}</>
452-
}}
453-
/>
436+
function App() {
437+
const form = useForm({
438+
defaultValues: {
439+
age: 0,
440+
},
441+
validators: {
442+
onChange: userSchema,
443+
},
444+
})
445+
return (
446+
<div>
447+
<form.Field
448+
name="age"
449+
children={(field) => {
450+
return <>{/* ... */}</>
451+
}}
452+
/>
453+
</div>
454+
)
455+
}
454456
```
455457
456-
These adapters also support async operations using the proper property names:
458+
Async validations on form and field level are supported as well:
457459
458460
```tsx
459461
<form.Field
@@ -477,44 +479,40 @@ These adapters also support async operations using the proper property names:
477479
/>
478480
```
479481
480-
### Form Level Adapter Validation
482+
### Other Schema Libraries
483+
484+
We also support [Yup](https://github.com/jquense/yup) through an official adapter:
481485
482-
You can also use the adapter at the form level:
486+
```bash
487+
$ npm install @tanstack/yup-form-adapter yup
488+
```
489+
490+
Once done, we can add the adapter to the `validator` property on the form or field:
483491
484492
```tsx
485-
import { zodValidator } from '@tanstack/zod-form-adapter'
486-
import { z } from 'zod'
493+
import { yupValidator } from '@tanstack/yup-form-adapter'
494+
import * as yup from 'yup'
487495
488496
// ...
489497
490-
const formSchema = z.object({
491-
age: z.number().gte(13, 'You must be 13 to make an account'),
492-
})
493-
494498
const form = useForm({
495-
validatorAdapter: zodValidator(),
496-
validators: {
497-
onChange: formSchema
498-
},
499+
// Either add the validator here or on `Field`
500+
validatorAdapter: yupValidator(),
501+
// ...
499502
})
500-
```
501-
502-
If you use the adapter at the form level, it will pass the validation to the fields of the same name.
503-
504-
This means that:
505-
506-
```tsx
507503
508504
<form.Field
509505
name="age"
506+
validatorAdapter={yupValidator()}
507+
validators={{
508+
onChange: yup.number().moreThan(13, 'You must be 13 to make an account'),
509+
}}
510510
children={(field) => {
511511
return <>{/* ... */}</>
512512
}}
513513
/>
514514
```
515515
516-
Will still display the error message from the form-level validation.
517-
518516
## Preventing invalid forms from being submitted
519517
520518
The `onChange`, `onBlur` etc... callbacks are also run when the form is submitted and the submission is blocked if the form is invalid.

0 commit comments

Comments
 (0)