diff --git a/docs/config.json b/docs/config.json
index e5d3199..37a38b0 100644
--- a/docs/config.json
+++ b/docs/config.json
@@ -30,8 +30,12 @@
"label": "Guides",
"children": [
{
- "label": "Important Defaults",
- "to": "guides/important-defaults"
+ "label": "Basic Concepts",
+ "to": "guides/basic-concepts"
+ },
+ {
+ "label": "Form Validation",
+ "to": "guides/validation"
}
]
},
@@ -89,6 +93,14 @@
{
"label": "Simple",
"to": "framework/react/examples/simple"
+ },
+ {
+ "label": "Yup",
+ "to": "framework/react/examples/yup"
+ },
+ {
+ "label": "Zod",
+ "to": "framework/react/examples/zod"
}
]
}
@@ -133,6 +145,14 @@
{
"label": "Simple",
"to": "framework/vue/examples/simple"
+ },
+ {
+ "label": "Yup",
+ "to": "framework/vue/examples/yup"
+ },
+ {
+ "label": "Zod",
+ "to": "framework/vue/examples/zod"
}
]
}
diff --git a/docs/guides/basic-concepts.md b/docs/guides/basic-concepts.md
index ed891ea..d849205 100644
--- a/docs/guides/basic-concepts.md
+++ b/docs/guides/basic-concepts.md
@@ -5,9 +5,7 @@ title: Basic Concepts and Terminology
# Basic Concepts and Terminology
-> Some of these docs may be inaccurate due to an API shift in `0.11.0`. If you're interested in helping us fix these issues, please [join our Discord](https://tlinz.com/discord) and reach out in the `#form` channel.
-
-This page introduces the basic concepts and terminology used in the @tanstack/react-form library. Familiarizing yourself with these concepts will help you better understand and work with the library.
+This page introduces the basic concepts and terminology used in the `@tanstack/react-form` library. Familiarizing yourself with these concepts will help you better understand and work with the library.
## Form Factory
@@ -86,7 +84,7 @@ Example:
## Validation
-@tanstack/react-form provides both synchronous and asynchronous validation out of the box. Validation functions can be passed to the form.Field component using the validate and validateAsync props.
+`@tanstack/react-form` provides both synchronous and asynchronous validation out of the box. Validation functions can be passed to the form.Field component using the validate and validateAsync props.
Example:
@@ -111,9 +109,34 @@ Example:
/>
```
+## Validation Adapters
+
+In addition to hand-rolled validation options, we also provide adapters like `@tanstack/zod-form-adapter` and `@tanstack/yup-form-adapter` to enable usage with common schema validation tools like [Yup](https://github.com/jquense/yup) and [Zod](https://zod.dev/).
+
+Example:
+
+```tsx
+
{
+ await new Promise((resolve) => setTimeout(resolve, 1000));
+ return !value.includes("error");
+ },
+ {
+ message: "No 'error' allowed in first name",
+ },
+ )}
+/>
+```
+
## Reactivity
-@tanstack/react-form offers various ways to subscribe to form and field state changes, such as the form.useStore hook, the form.Subscribe component, and the form.useField hook. These methods allow you to optimize your form's rendering performance by only updating components when necessary.
+`@tanstack/react-form` offers various ways to subscribe to form and field state changes, such as the `form.useStore` hook, the `form.Subscribe` component, and the `form.useField` hook. These methods allow you to optimize your form's rendering performance by only updating components when necessary.
Example:
@@ -240,8 +263,5 @@ Example:
/>
```
-These are the basic concepts and terminology used in the @tanstack/react-form library. Understanding these concepts will help you work more effectively with the library and create complex forms with ease.
+These are the basic concepts and terminology used in the `@tanstack/react-form` library. Understanding these concepts will help you work more effectively with the library and create complex forms with ease.
-```
-
-```
diff --git a/docs/guides/important-defaults.md b/docs/guides/important-defaults.md
deleted file mode 100644
index d958531..0000000
--- a/docs/guides/important-defaults.md
+++ /dev/null
@@ -1,21 +0,0 @@
----
-id: important-defaults
-title: Important Defaults
----
-
-> Some of these docs may be inaccurate due to an API shift in `0.11.0`. If you're interested in helping us fix these issues, please [join our Discord](https://tlinz.com/discord) and reach out in the `#form` channel.
-
-Out of the box, TanStack Form is configured with **aggressive but sane** defaults. **Sometimes these defaults can catch new users off guard or make learning/debugging difficult if they are unknown by the user.** Keep them in mind as you continue to learn and use TanStack Form:
-
-- Core
- - Validation
- - By default, only touched, dirty fields are validated on blur and submit. This means that if you have a field that is required, it will not show an error until the user has blurred the field (focused and unfocused) or submitted the form. You can change this to include field `change` events or only the `submit` event with a form default or on a per field basis with the `defaultValidateOn` and `validateOn` options. `validatePristine` can also be used to validate pristine fields.
- - By default, TanStack async validation will only run if synchronous validation succeeds. This is to prevent unnecessary async validation which usually are powered by network requests.
- - By default, TanStack Form will not validate fields that are not registered. This is to prevent unnecessary validation of fields that are not in the DOM. This can be changed with the `validateUnregistered` option.
-- React
- - Reactivity
- - The `useForm` hook and `form.Form` component are not reactive, which means that as _any_ form state changes, they will not rerender. If they did, you would likely run into performance problems very quickly. Instead, use:
- - `form.useStore` to subscribe and rerender when form state changes. Selectors are supported.
- - `form.Subscribe` to render a specific sub-tree of UI that is subscribed to the form state. Selectors are supported.
- - `form.useField` to subscribe to a specific field's state changes.
- - `form.Field` **is reactive** to all state changes that happen within a field. This means that as a field's value, error, touched, etc. changes, the component you use it in will rerender. This is a good thing because it means you don't have to worry about manually subscribing to a field's state changes.
diff --git a/docs/guides/validation.md b/docs/guides/validation.md
new file mode 100644
index 0000000..6abd829
--- /dev/null
+++ b/docs/guides/validation.md
@@ -0,0 +1,280 @@
+---
+id: form-validation
+title: Form and Field Validation
+---
+
+# Form and Field Validation
+
+At the core of TanStack Form's functionalities is the concept of validation. We currently support three mechanisms of validation:
+
+- Synchronous functional validation
+- Asynchronous functional validation
+- Adapter-based validation
+
+Let's take a look at each and see how they're built.
+
+## Synchronous Functional Validation
+
+With Form, you can pass a function to a field and, if it returns a string, said string will be used as the error:
+
+```tsx
+ val < 13 ? "You must be 13 to make an account" : undefined}
+ children={(field) => {
+ return (
+ <>
+
+ field.handleChange(e.target.valueAsNumber)}
+ />
+ {field.state.meta.touchedErrors ? (
+ {field.state.meta.touchedErrors}
+ ) : null}
+ >
+ );
+ }}
+/>
+```
+
+### Displaying Errors
+
+Once you have your validation in place, you can map the errors from an array to be displayed in your UI:
+
+```tsx
+ val < 13 ? "You must be 13 to make an account" : undefined}
+ children={(field) => {
+ return (
+ <>
+ {/* ... */}
+ {field.state.meta.errors ? (
+ {field.state.meta.errors}
+ ) : null}
+ >
+ );
+ }}
+/>
+```
+
+Or use the `errorMap` property to access the specific error you're looking for:
+
+```tsx
+ val < 13 ? "You must be 13 to make an account" : undefined}
+ children={(field) => {
+ return (
+ <>
+ {/* ... */}
+ {field.state.meta.errorMap['onChange'] ? (
+ {field.state.meta.errorMap['onChange']}
+ ) : null}
+ >
+ );
+ }}
+/>
+```
+
+### Using Alternative Validation Steps
+
+One of the great benefits of using TanStack Form is that you're not locked into a specific method of validation. For example, if you want to validate a specific field on blur rather than on text change, you can change `onChange` to `onBlur`:
+
+```tsx
+ val < 13 ? "You must be 13 to make an account" : undefined}
+ children={(field) => {
+ return (
+ <>
+ {/* ... */}
+ >
+ );
+ }}
+/>
+```
+
+## Asynchronous Functional Validation
+
+While we suspect most validations will be synchronous, there's many instances where a network call or some other async operation would be useful to validate against.
+
+To do this, we have dedicated `onChangeAsync`, `onBlurAsync`, and other methods that can be used to validate against:
+
+```tsx
+ {
+ await new Promise((resolve) => setTimeout(resolve, 1000));
+ return (
+ value.includes("error") && 'No "error" allowed in first name'
+ );
+ }}
+ children={(field) => {
+ return (
+ <>
+
+ field.handleChange(e.target.value)}
+ />
+
+ >
+ );
+ }}
+/>
+```
+
+This can be combined with the respective synchronous properties as well:
+
+``` tsx
+
+ !value
+ ? "A first name is required"
+ : value.length < 3
+ ? "First name must be at least 3 characters"
+ : undefined
+ }
+ onChangeAsync={async (value) => {
+ await new Promise((resolve) => setTimeout(resolve, 1000));
+ return (
+ value.includes("error") && 'No "error" allowed in first name'
+ );
+ }}
+ children={(field) => {
+ return (
+ <>
+ {/* ... */}
+ >
+ );
+ }}
+/>
+```
+
+### Built-in Debouncing
+
+While async calls are the way to go when validating against the database, running a network request on every keystroke is a good way to DDOS your database.
+
+Instead, we enable an easy method for debouncing your `async` calls by adding a single property:
+
+```tsx
+ {
+ // ...
+ }}
+ children={(field) => {
+ return (
+ <>
+ {/* ... */}
+ >
+ );
+ }}
+/>
+```
+
+This will debounce every async call with a 500ms delay. You can even override this property on a per-validation property:
+
+```tsx
+ {
+ // ...
+ }}
+ onBlurAsync={async (value) => {
+ // ...
+ }}
+ children={(field) => {
+ return (
+ <>
+ {/* ... */}
+ >
+ );
+ }}
+/>
+```
+
+> This will run `onChangeAsync` every 1500ms while `onBlurAsync` will run every 500ms.
+
+
+## Adapter-Based Validation
+
+While functions provide more flexibility and customization over your validation, they can be a bit verbose. To help solve this, there are libraries like [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.
+
+Luckily, we support both of these libraries through official adapters:
+
+```bash
+$ npm install @tanstack/zod-form-adapter zod
+# or
+$ npm install @tanstack/yup-form-adapter yup
+```
+
+Once done, we can add the adapter to the `validator` property on the form or field:
+
+```tsx
+import { zodValidator } from "@tanstack/zod-form-adapter";
+import { z } from "zod";
+
+// ...
+
+const form = useForm({
+ // Either add the validator here or on `Field`
+ validator: zodValidator,
+ // ...
+});
+
+ {
+ return (
+ <>
+ {/* ... */}
+ >
+ );
+ }}
+/>
+```
+
+These adapters also support async operations using the proper property names:
+
+```tsx
+ {
+ await new Promise((resolve) => setTimeout(resolve, 1000));
+ return !value.includes("error");
+ },
+ {
+ message: "No 'error' allowed in first name",
+ },
+ )}
+ children={(field) => {
+ return (
+ <>
+ {/* ... */}
+ >
+ );
+ }}
+/>
+```
+
diff --git a/docs/installation.md b/docs/installation.md
index b2c090b..ec50d39 100644
--- a/docs/installation.md
+++ b/docs/installation.md
@@ -3,11 +3,20 @@ id: installation
title: Installation
---
-While the core of TanStack Form is framework-agnostic and will be compatible with various front-end frameworks in the future, we only support React today.
-To use TanStack Form with React, install the adapter via NPM
+TanStack Form is compatible with various front-end frameworks, including React and Vue. To use TanStack Form with your desired framework, install the corresponding adapter via NPM:
```bash
$ npm i @tanstack/react-form
+# or
+$ pnpm add @tanstack/vue-form
```
> Depending on your environment, you might need to add polyfills. If you want to support older browsers, you need to transpile the library from `node_modules` yourselves.
+
+In addition, we support both Zod and Yup as validators through official validator packages:
+
+```bash
+$ yarn add @tanstack/zod-form-adapter zod
+# or
+$ npm i @tanstack/yup-form-adapter yup
+```
diff --git a/docs/reference/fieldApi.md b/docs/reference/fieldApi.md
index 9934fa4..78ca185 100644
--- a/docs/reference/fieldApi.md
+++ b/docs/reference/fieldApi.md
@@ -11,24 +11,44 @@ Normally, you will not need to create a new `FieldApi` instance directly. Instea
const fieldApi: FieldApi = new FieldApi(formOptions: Field Options)
```
-### `FieldOptions`
+### `FieldOptions`
An object type representing the options for a field in a form.
- ```tsx
- name
+ name: TName
```
- - The field name. If `TParentData` is `unknown`, the type will be `string`. Otherwise, it will be `DeepKeys`.
+ - The field name. The type will be `DeepKeys` to ensure your name is a deep key of the parent dataset.
+
- ```tsx
defaultValue?: TData
```
- An optional default value for the field.
+
- ```tsx
defaultMeta?: Partial
```
- An optional object with default metadata for the field.
+- ```tsx
+ asyncDebounceMs?: number
+ ```
+
+ - The default time to debounce async validation if there is not a more specific debounce time passed.
+
+- ```tsx
+ asyncAlways?: boolean
+ ```
+
+ - If `true`, always run async validation, even if there are errors emitted during synchronous validation.
+
+- ```typescript
+ validator?: ValidatorType
+ ```
+
+ - A validator provided by an extension, like `yupValidator` from `@tanstack/yup-form-adapter`
+
- ```tsx
onMount?: (formApi: FieldApi) => void
```
@@ -36,35 +56,35 @@ An object type representing the options for a field in a form.
- An optional function that takes a param of `formApi` which is a generic type of `TData` and `TParentData`
- ```tsx
- onChange?: ValidateFn
+ onChange?: ValidateFn
```
- - An optional property that takes a `ValidateFn` which is a generic of `TData` and `TParentData`
+ - An optional property that takes a `ValidateFn` which is a generic of `TData` and `TParentData`. If `validator` is passed, this may also accept a property from the respective validator (IE: `z.string().min(1)` if `zodAdapter` is passed)
- ```tsx
- onChangeAsync?: ValidateAsyncFn
+ onChangeAsync?: ValidateAsyncFn
```
- - An optional property similar to `onChange` but async validation
+ - An optional property similar to `onChange` but async validation. If `validator` is passed, this may also accept a property from the respective validator (IE: `z.string().refine(async (val) => val.length > 3, { message: 'Testing 123' })` if `zodAdapter` is passed)
- ```tsx
- onChangeAsyncDebounceMs?: number
+ onChangeAsyncDebounceMs?: number
```
- An optional number to represent how long the `onChangeAsync` should wait before running
- If set to a number larger than 0, will debounce the async validation event by this length of time in milliseconds
- ```tsx
- onBlur?: ValidateFn
+ onBlur?: ValidateFn
```
- - An optional function, when that run when subscribing to blur event of input
+ - An optional function, when that run when subscribing to blur event of input. If `validator` is passed, this may also accept a property from the respective validator (IE: `z.string().min(1)` if `zodAdapter` is passed)
- ```tsx
- onBlurAsync?: ValidateAsyncFn
+ onBlurAsync?: ValidateAsyncFn
```
- - An optional function that takes a `ValidateFn` which is a generic of `TData` and `TParentData` happens async
+ - An optional function that takes a `ValidateFn` which is a generic of `TData` and `TParentData` happens async. If `validator` is passed, this may also accept a property from the respective validator (IE: `z.string().refine(async (val) => val.length > 3, { message: 'Testing 123' })` if `zodAdapter` is passed)
```tsx
onBlurAsyncDebounceMs?: number
@@ -77,13 +97,15 @@ An object type representing the options for a field in a form.
onSubmitAsync?: number
```
- - If set to a number larger than 0, will debounce the async validation event by this length of time in milliseconds
+ - If set to a number larger than 0, will debounce the async validation event by this length of time in milliseconds. If `validator` is passed, this may also accept a property from the respective validator (IE: `z.string().refine(async (val) => val.length > 3, { message: 'Testing 123' })` if `zodAdapter` is passed)
### `ValidationCause`
A type representing the cause of a validation event.
-- 'change' | 'blur' | 'submit' | 'mount'
+- ```tsx
+ 'change' | 'blur' | 'submit' | 'mount'
+ ```
### `FieldMeta`
@@ -127,7 +149,7 @@ A class representing the API for managing a form field.
```
- A unique identifier for the field instance.
- ```tsx
- form: FormApi
+ form: FormApi
```
- A reference to the form API instance.
- ```tsx
@@ -153,66 +175,77 @@ A class representing the API for managing a form field.
constructor(opts: FieldApiOptions)
```
- Initializes a new `FieldApi` instance.
+
- ```tsx
mount(): () => void
```
- Mounts the field instance to the form.
-- ```tsx
- updateStore(): void
- ```
- - Updates the field store with the latest form state.
+
- ```tsx
update(opts: FieldApiOptions): void
```
- Updates the field instance with new options.
+
- ```tsx
getValue(): TData
```
- Gets the current field value.
+
- ```tsx
setValue(updater: Updater, options?: { touch?: boolean; notify?: boolean }): void
```
- - Sets the field value.
+ - Sets the field value and run the `change` validator.
+
- ```tsx
getMeta(): FieldMeta
```
- Gets the current field metadata.
+
- ```tsx
setMeta(updater: Updater): void
```
- Sets the field metadata.
+
- ```tsx
getInfo(): any
```
- Gets the field information object.
+
- ```tsx
pushValue(value: TData): void
```
- Pushes a new value to the field.
+
- ```tsx
insertValue(index: number, value: TData): void
```
- Inserts a value at the specified index.
+
- ```tsx
removeValue(index: number): void
```
- Removes a value at the specified index.
+
- ```tsx
swapValues(aIndex: number, bIndex: number): void
```
- Swaps the values at the specified indices.
+
- ```tsx
- getSubField>(name: TName): FieldApi, TParentData>
+ getSubField(name: TName): FieldApi
```
- Gets a subfield instance.
+
- ```tsx
validate(): Promise
```
- Validates the field value.
+
- ```tsx
handleBlur(): void;
```
- Handles the blur event.
+
- ```tsx
handleChange(value: TData): void
```
@@ -231,62 +264,3 @@ An object type representing the state of a field.
```
- The current metadata of the field.
-### `UserChangeProps`
-
-An object type representing the change and blur event handlers for a field.
-
-- ```tsx
- onChange?: (value: TData) => void
- ```
- - An optional function to further handle the change event.
-- ```tsx
- onBlur?: (event: any) => void
- ```
- - An optional function to further handle the blur event.
-
-### `UserInputProps`
-
-An object type representing the input event handlers for a field.
-
-- ```tsx
- onChange?: (event: any) => void
- ```
- - An optional function to further handle the change event.
-- ```tsx
- onBlur?: (event: any) => void
- ```
- - An optional function to further handle the blur event.
-
-### `ChangeProps`
-
-An object type representing the change and blur event handlers for a field.
-
-- ```tsx
- value: TData
- ```
- - The current value of the field.
-- ```tsx
- onChange: (value: TData) => void
- ```
- - A function to handle the change event.
-- ```tsx
- onBlur: (event: any) => void
- ```
- - A function to handle the blur event.
-
-### `InputProps`
-
-An object type representing the input event handlers for a field.
-
-- ```tsx
- value: string
- ```
- - The current value of the field, coerced to a string.
-- ```tsx
- onChange: (event: any) => void
- ```
- - A function to handle the change event.
-- ```tsx
- onBlur: (event: any) => void
- ```
- - A function to handle the blur event.
diff --git a/docs/reference/formApi.md b/docs/reference/formApi.md
index e6cbc62..84b5bcd 100644
--- a/docs/reference/formApi.md
+++ b/docs/reference/formApi.md
@@ -13,14 +13,14 @@ Normally, you will not need to create a new `FormApi` instance directly. Instead
const formApi: FormApi = new FormApi(formOptions: FormOptions)
```
-### `FormOptions`
+### `FormOptions`
An object representing the options for a form.
- ```tsx
defaultValues?: TData
```
- - Set initial values for you form.
+ - Set initial values for yonu form.
- ```tsx
defaultState?: Partial>
```
@@ -32,7 +32,7 @@ An object representing the options for a form.
- Optional time in milliseconds if you want to introduce a delay before firing off an async action.
- ```tsx
- onMount?: (values: TData, formApi: FormApi) => ValidationError
+ onMount?: (values: TData, formApi: FormApi) => ValidationError
```
- Optional function that fires as soon as the component mounts.
- ```tsx
@@ -75,7 +75,7 @@ An object representing the options for a form.
- The default time in milliseconds that if set to a number larger than 0, will debounce the async validation event by this length of time in milliseconds.
- ```tsx
- onSubmit?: (values: TData, formApi: FormApi) => any | Promise
+ onSubmit?: (values: TData, formApi: FormApi) => any | Promise
```
- A function to be called when the form is submitted, what should happen once the user submits a valid form returns `any` or a promise `Promise`
@@ -85,7 +85,7 @@ An object representing the options for a form.
- Specify an action for scenarios where the user tries to submit an invalid form.
-### `FormApi`
+### `FormApi`
A class representing the Form API. It handles the logic and interactions with the form state.
@@ -136,9 +136,9 @@ A class representing the Form API. It handles the logic and interactions with th
- Validates all fields in the form.
- ```tsx
- handleSubmit(e: FormSubmitEvent)
+ handleSubmit()
```
- - Handles the form submission event, performs validation, and calls the appropriate onSubmit or onInvalidSubmit callbacks.
+ - Handles the form submission, performs validation, and calls the appropriate onSubmit or onInvalidSubmit callbacks.
- ```tsx
getFieldValue>(field: TField)
```
diff --git a/examples/react/simple/package.json b/examples/react/simple/package.json
index 4848925..8f19f77 100644
--- a/examples/react/simple/package.json
+++ b/examples/react/simple/package.json
@@ -12,9 +12,7 @@
"axios": "^0.26.1",
"react": "^18.0.0",
"react-dom": "^18.0.0",
- "zod": "^3.21.4",
- "@tanstack/form-core": "0.3.7",
- "@tanstack/vue-form": "0.3.7"
+ "@tanstack/form-core": "0.3.7"
},
"devDependencies": {
"@vitejs/plugin-react": "^4.0.4",
diff --git a/examples/react/simple/src/index.tsx b/examples/react/simple/src/index.tsx
index 920f9cf..295009d 100644
--- a/examples/react/simple/src/index.tsx
+++ b/examples/react/simple/src/index.tsx
@@ -3,7 +3,7 @@ import { createRoot } from "react-dom/client";
import { useForm } from "@tanstack/react-form";
import type { FieldApi } from "@tanstack/react-form";
-function FieldInfo({ field }: { field: FieldApi }) {
+function FieldInfo({ field }: { field: FieldApi }) {
return (
<>
{field.state.meta.touchedErrors ? (
diff --git a/examples/react/yup/.eslintrc.cjs b/examples/react/yup/.eslintrc.cjs
new file mode 100644
index 0000000..201e653
--- /dev/null
+++ b/examples/react/yup/.eslintrc.cjs
@@ -0,0 +1,15 @@
+// @ts-check
+
+/** @type {import('eslint').Linter.Config} */
+const config = {
+ extends: ["plugin:react/recommended", "plugin:react-hooks/recommended"],
+ parserOptions: {
+ tsconfigRootDir: __dirname,
+ project: "./tsconfig.json",
+ },
+ rules: {
+ "react/no-children-prop": "off",
+ },
+};
+
+module.exports = config;
diff --git a/examples/react/yup/.gitignore b/examples/react/yup/.gitignore
new file mode 100644
index 0000000..4673b02
--- /dev/null
+++ b/examples/react/yup/.gitignore
@@ -0,0 +1,27 @@
+# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
+
+# dependencies
+/node_modules
+/.pnp
+.pnp.js
+
+# testing
+/coverage
+
+# production
+/build
+
+pnpm-lock.yaml
+yarn.lock
+package-lock.json
+
+# misc
+.DS_Store
+.env.local
+.env.development.local
+.env.test.local
+.env.production.local
+
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
diff --git a/examples/react/yup/.prettierrc b/examples/react/yup/.prettierrc
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/examples/react/yup/.prettierrc
@@ -0,0 +1 @@
+{}
diff --git a/examples/react/yup/README.md b/examples/react/yup/README.md
new file mode 100644
index 0000000..1cf8892
--- /dev/null
+++ b/examples/react/yup/README.md
@@ -0,0 +1,6 @@
+# Example
+
+To run this example:
+
+- `npm install`
+- `npm run dev`
diff --git a/examples/react/yup/index.html b/examples/react/yup/index.html
new file mode 100644
index 0000000..d717e9d
--- /dev/null
+++ b/examples/react/yup/index.html
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+ TanStack Form React Yup Example App
+
+
+
+
+
+
+
diff --git a/examples/react/yup/package.json b/examples/react/yup/package.json
new file mode 100644
index 0000000..8266279
--- /dev/null
+++ b/examples/react/yup/package.json
@@ -0,0 +1,49 @@
+{
+ "name": "@tanstack/form-example-react-yup",
+ "version": "0.0.1",
+ "main": "src/index.jsx",
+ "scripts": {
+ "dev": "vite --port=3001",
+ "build": "vite build",
+ "preview": "vite preview"
+ },
+ "dependencies": {
+ "@tanstack/react-form": "0.3.7",
+ "axios": "^0.26.1",
+ "react": "^18.0.0",
+ "react-dom": "^18.0.0",
+ "yup": "^1.3.2",
+ "@tanstack/form-core": "0.3.7",
+ "@tanstack/yup-form-adapter": "0.3.7"
+ },
+ "devDependencies": {
+ "@vitejs/plugin-react": "^4.0.4",
+ "vite": "^4.4.9"
+ },
+ "browserslist": {
+ "production": [
+ ">0.2%",
+ "not dead",
+ "not op_mini all"
+ ],
+ "development": [
+ "last 1 chrome version",
+ "last 1 firefox version",
+ "last 1 safari version"
+ ]
+ },
+ "nx": {
+ "implicitDependencies": [
+ "@tanstack/form-core",
+ "@tanstack/react-form",
+ "@tanstack/yup-form-adapter"
+ ],
+ "targets": {
+ "test:types": {
+ "dependsOn": [
+ "build"
+ ]
+ }
+ }
+ }
+}
diff --git a/examples/react/yup/public/emblem-light.svg b/examples/react/yup/public/emblem-light.svg
new file mode 100644
index 0000000..a58e69a
--- /dev/null
+++ b/examples/react/yup/public/emblem-light.svg
@@ -0,0 +1,13 @@
+
+
\ No newline at end of file
diff --git a/examples/react/yup/src/index.tsx b/examples/react/yup/src/index.tsx
new file mode 100644
index 0000000..38d15e7
--- /dev/null
+++ b/examples/react/yup/src/index.tsx
@@ -0,0 +1,114 @@
+import * as React from "react";
+import { createRoot } from "react-dom/client";
+import { useForm } from "@tanstack/react-form";
+import { yupValidator } from "@tanstack/yup-form-adapter";
+import * as yup from "yup";
+import type { FieldApi } from "@tanstack/react-form";
+
+function FieldInfo({ field }: { field: FieldApi }) {
+ return (
+ <>
+ {field.state.meta.touchedErrors ? (
+ {field.state.meta.touchedErrors}
+ ) : null}
+ {field.state.meta.isValidating ? "Validating..." : null}
+ >
+ );
+}
+
+export default function App() {
+ const form = useForm({
+ // Memoize your default values to prevent re-renders
+ defaultValues: {
+ firstName: "",
+ lastName: "",
+ },
+ onSubmit: async (values) => {
+ // Do something with form data
+ console.log(values);
+ },
+ // Add a validator to support Yup usage in Form and Field
+ validator: yupValidator,
+ });
+
+ return (
+