;
+
+ return null;
+}
+
+```
+
+This will show a loading spinner until the data is fetched, and then it will render the form with the fetched data as the initial values.
diff --git a/docs/framework/solid/guides/basic-concepts.md b/docs/framework/solid/guides/basic-concepts.md
new file mode 100644
index 000000000..eb3cf2a13
--- /dev/null
+++ b/docs/framework/solid/guides/basic-concepts.md
@@ -0,0 +1,288 @@
+---
+id: basic-concepts
+title: Basic Concepts and Terminology
+---
+
+This page introduces the basic concepts and terminology used in the `@tanstack/solid-form` library. Familiarizing yourself with these concepts will help you better understand and work with the library.
+
+## Form Options
+
+You can create options for your form so that it can be shared between multiple forms by using the `formOptions` function.
+
+Example:
+
+```tsx
+const formOpts = formOptions({
+ defaultValues: {
+ firstName: '',
+ lastName: '',
+ hobbies: [],
+ },
+})
+```
+
+## Form Instance
+
+A Form Instance is an object that represents an individual form and provides methods and properties for working with the form. You create a form instance using the `createForm` hook provided by the form options. The hook accepts an object with an `onSubmit` function, which is called when the form is submitted.
+
+```tsx
+const form = createForm(() => ({
+ ...formOpts,
+ onSubmit: async ({ value }) => {
+ // Do something with form data
+ console.log(value);
+ },
+}))
+```
+
+You may also create a form instance without using `formOptions` by using the standalone `createForm` API:
+
+```tsx
+const form = createForm(() => ({
+ onSubmit: async ({ value }) => {
+ // Do something with form data
+ console.log(value);
+ },
+ defaultValues: {
+ firstName: '',
+ lastName: '',
+ hobbies: [],
+ },
+}))
+```
+
+## Field
+
+A Field represents a single form input element, such as a text input or a checkbox. Fields are created using the `form.Field` component provided by the form instance. The component accepts a name prop, which should match a key in the form's default values. It also accepts a children prop, which is a render prop function that takes a field object as its argument.
+
+Example:
+
+```tsx
+ (
+ field().handleChange(e.target.value)}
+ />
+ )}
+/>
+```
+
+## Field State
+
+Each field has its own state, which includes its current value, validation status, error messages, and other metadata. You can access a field's state using the `field().state` property.
+
+Example:
+
+```tsx
+const { value, meta: { errors, isValidating } } = field().state
+```
+
+There are three field states can be very useful to see how the user interacts with a field. A field is _"touched"_ when the user clicks/tabs into it, _"pristine"_ until the user changes value in it, and _"dirty"_ after the value has been changed. You can check these states via the `isTouched`, `isPristine` and `isDirty` flags, as seen below.
+
+```tsx
+const { isTouched, isPristine, isDirty } = field().state.meta
+```
+
+![Field states](https://raw.githubusercontent.com/TanStack/form/main/docs/assets/field-states.png)
+
+## Field API
+
+The Field API is an object passed to the render prop function when creating a field. It provides methods for working with the field's state.
+
+Example:
+
+```tsx
+ field().handleChange(e.target.value)}
+/>
+```
+
+## Validation
+
+`@tanstack/solid-form` provides both synchronous and asynchronous validation out of the box. Validation functions can be passed to the `form.Field` component using the `validators` prop.
+
+Example:
+
+```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) => (
+ <>
+ field().handleChange(e.target.value)}
+ />
+
{field().state.meta.errors[0]}
+ >
+ )}
+/>
+```
+
+## Validation Adapters
+
+In addition to hand-rolled validation options, we also provide adapters like `@tanstack/zod-form-adapter`, `@tanstack/yup-form-adapter`, and `@tanstack/valibot-form-adapter` to enable usage with common schema validation tools like [Zod](https://zod.dev/), [Yup](https://github.com/jquense/yup), and [Valibot](https://valibot.dev/).
+
+Example:
+
+```tsx
+import { zodValidator } from '@tanstack/zod-form-adapter'
+import { z } from 'zod'
+
+// ...
+ {
+ await new Promise((resolve) => setTimeout(resolve, 1000));
+ return !value.includes('error');
+ },
+ {
+ message: 'No "error" allowed in first name',
+ }
+ ),
+ }}
+ children={(field) => (
+ <>
+ field().handleChange(e.target.value)}
+ />
+
{field().state.meta.errors[0]}
+ >
+ )}
+/>
+```
+
+## Reactivity
+
+`@tanstack/solid-form` offers various ways to subscribe to form and field state changes, most notably the `form.useStore` hook and the `form.Subscribe` component. These methods allow you to optimize your form's rendering performance by only updating components when necessary.
+
+Example:
+
+```tsx
+const firstName = form.useStore((state) => state.values.firstName)
+//...
+ ({
+ canSubmit: state.canSubmit,
+ isSubmitting: state.isSubmitting,
+ })}
+ children={(state) => (
+
+ )}
+/>
+```
+
+## Array Fields
+
+Array fields allow you to manage a list of values within a form, such as a list of hobbies. You can create an array field using the `form.Field` component with the `mode="array"` prop.
+
+When working with array fields, you can use the fields `pushValue`, `removeValue`, `swapValues` and `moveValue` methods to add, remove, and swap values in the array.
+
+Example:
+
+```tsx
+ (
+
+ )}
+/>
+```
+
+These are the basic concepts and terminology used in the `@tanstack/solid-form` library. Understanding these concepts will help you work more effectively with the library and create complex forms with ease.
diff --git a/docs/framework/solid/guides/linked-fields.md b/docs/framework/solid/guides/linked-fields.md
new file mode 100644
index 000000000..9c9757208
--- /dev/null
+++ b/docs/framework/solid/guides/linked-fields.md
@@ -0,0 +1,77 @@
+---
+id: linked-fields
+title: Link Two Form Fields Together
+---
+
+You may find yourself needing to link two fields together; when one is validated as another field's value has changed.
+One such usage is when you have both a `password` and `confirm_password` field,
+where you want to `confirm_password` to error out when `password`'s value does not match;
+regardless of which field triggered the value change.
+
+Imagine the following userflow:
+
+- User updates confirm password field.
+- User updates the non-confirm password field.
+
+In this example, the form will still have errors present,
+as the "confirm password" field validation has not been re-ran to mark as accepted.
+
+To solve this, we need to make sure that the "confirm password" validation is re-run when the password field is updated.
+To do this, you can add a `onChangeListenTo` property to the `confirm_password` field.
+
+```tsx
+export default function App() {
+ const form = createForm(() => ({
+ defaultValues: {
+ password: '',
+ confirm_password: '',
+ },
+ // ...
+ }));
+
+ return (
+
+ );
+}
+```
+
+This similarly works with `onBlurListenTo` property, which will re-run the validation when the field is blurred.
diff --git a/docs/framework/solid/guides/validation.md b/docs/framework/solid/guides/validation.md
new file mode 100644
index 000000000..354b721bb
--- /dev/null
+++ b/docs/framework/solid/guides/validation.md
@@ -0,0 +1,406 @@
+---
+id: form-validation
+title: Form and Field Validation
+---
+
+At the core of TanStack Form's functionalities is the concept of validation. TanStack Form makes validation highly customizable:
+
+- You can control when to perform the validation (on change, on input, on blur, on submit...)
+- Validation rules can be defined at the field level or at the form level
+- Validation can be synchronous or asynchronous (for example, as a result of an API call)
+
+## When is validation performed?
+
+It's up to you! The `` component accepts some callbacks as props such as `onChange` or `onBlur`. Those callbacks are passed the current value of the field, as well as the fieldAPI object, so that you can perform the validation. If you find a validation error, simply return the error message as string and it will be available in `field().state.meta.errors`.
+
+Here is an example:
+
+```tsx
+
+ value < 13 ? 'You must be 13 to make an account' : undefined,
+ }}
+>
+ {(field) => (
+ <>
+
+ field().handleChange(e.target.valueAsNumber)}
+ />
+ {field().state.meta.errors ? (
+ {field().state.meta.errors.join(', ')}
+ ) : null}
+ >
+ )}
+
+```
+
+In the example above, the validation is done at each keystroke (`onChange`). If, instead, we wanted the validation to be done when the field is blurred, we would change the code above like so:
+
+```tsx
+
+ value < 13 ? 'You must be 13 to make an account' : undefined,
+ }}
+>
+ {(field) => (
+ <>
+
+ field().handleChange(e.target.valueAsNumber)}
+ />
+ {field().state.meta.errors ? (
+ {field().state.meta.errors.join(', ')}
+ ) : null}
+ >
+ )}
+
+```
+
+So you can control when the validation is done by implementing the desired callback. You can even perform different pieces of validation at different times:
+
+```tsx
+
+ value < 13 ? 'You must be 13 to make an account' : undefined,
+ onBlur: ({ value }) => (value < 0 ? 'Invalid value' : undefined),
+ }}
+>
+ {(field) => (
+ <>
+
+ field().handleChange(e.target.valueAsNumber)}
+ />
+ {field().state.meta.errors ? (
+ {field().state.meta.errors.join(', ')}
+ ) : null}
+ >
+ )}
+
+```
+
+In the example above, we are validating different things on the same field at different times (at each keystroke and when blurring the field). Since `field().state.meta.errors` is an array, all the relevant errors at a given time are displayed. You can also use `field().state.meta.errorMap` to get errors based on _when_ the validation was done (onChange, onBlur etc...). More info about displaying errors below.
+
+## Displaying Errors
+
+Once you have your validation in place, you can map the errors from an array to be displayed in your UI:
+
+```tsx
+
+ value < 13 ? 'You must be 13 to make an account' : undefined,
+ }}
+>
+ {(field) => {
+ return (
+ <>
+ {/* ... */}
+ {field().state.meta.errors.length ? (
+ {field().state.meta.errors.join(',')}
+ ) : null}
+ >
+ );
+ }}
+
+```
+
+Or use the `errorMap` property to access the specific error you're looking for:
+
+```tsx
+
+ value < 13 ? 'You must be 13 to make an account' : undefined,
+ }}
+>
+ {(field) => (
+ <>
+ {/* ... */}
+ {field().state.meta.errorMap['onChange'] ? (
+ {field().state.meta.errorMap['onChange']}
+ ) : null}
+ >
+ )}
+
+```
+
+## Validation at field level vs at form level
+
+As shown above, each `` accepts its own validation rules via the `onChange`, `onBlur` etc... callbacks. It is also possible to define validation rules at the form level (as opposed to field by field) by passing similar callbacks to the `createForm()` hook.
+
+Example:
+
+```tsx
+export default function App() {
+ const form = createForm(() => ({
+ defaultValues: {
+ age: 0,
+ },
+ onSubmit: async ({ value }) => {
+ console.log(value);
+ },
+ validators: {
+ // Add validators to the form the same way you would add them to a field
+ onChange({ value }) {
+ if (value.age < 13) {
+ return 'Must be 13 or older to sign';
+ }
+ return undefined;
+ },
+ },
+ }));
+
+ // Subscribe to the form's error map so that updates to it will render
+ // alternately, you can use `form.Subscribe`
+ const formErrorMap = form.useStore((state) => state.errorMap);
+
+ return (
+
+ {/* ... */}
+ {formErrorMap().onChange ? (
+
+ There was an error on the form: {formErrorMap().onChange}
+
+ ) : null}
+ {/* ... */}
+
+ );
+}
+```
+
+## Asynchronous Functional Validation
+
+While we suspect most validations will be synchronous, there are 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 < 13 ? 'You must be 13 to make an account' : undefined;
+ },
+ }}
+>
+ {(field) => (
+ <>
+
+ field().handleChange(e.target.valueAsNumber)}
+ />
+ {field().state.meta.errors ? (
+ {field().state.meta.errors.join(', ')}
+ ) : null}
+ >
+ )}
+
+```
+
+Synchronous and Asynchronous validations can coexist. For example, it is possible to define both `onBlur` and `onBlurAsync` on the same field:
+
+```tsx
+ (value < 13 ? 'You must be at least 13' : undefined),
+ onBlurAsync: async ({ value }) => {
+ const currentAge = await fetchCurrentAgeOnProfile();
+ return value < currentAge ? 'You can only increase the age' : undefined;
+ },
+ }}
+>
+ {(field) => (
+ <>
+
+ field().handleChange(e.target.valueAsNumber)}
+ />
+ {field().state.meta.errors ? (
+ {field().state.meta.errors.join(', ')}
+ ) : null}
+ >
+ )}
+
+```
+
+The synchronous validation method (`onBlur`) is run first and the asynchronous method (`onBlurAsync`) is only run if the synchronous one (`onBlur`) succeeds. To change this behaviour, set the `asyncAlways` option to `true`, and the async method will be run regardless of the result of the sync method.
+
+### 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 (Zod, Yup, Valibot)
+
+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.
+
+Luckily, we support all of these libraries through official adapters:
+
+```bash
+$ npm install @tanstack/zod-form-adapter zod
+# or
+$ npm install @tanstack/yup-form-adapter yup
+# or
+$ npm install @tanstack/valibot-form-adapter valibot
+```
+
+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 = createForm(() => ({
+ // Either add the validator here or on `Field`
+ validatorAdapter: zodValidator(),
+ // ...
+}));
+
+ {
+ return <>{/* ... */}>
+ }}
+/>
+```
+
+These adapters also support async operations using the proper property names:
+
+```tsx
+ {
+ const currentAge = await fetchCurrentAgeOnProfile()
+ return value >= currentAge
+ },
+ {
+ message: 'You can only increase the age',
+ },
+ ),
+ }}
+ children={(field) => {
+ return <>{/* ... */}>
+ }}
+/>
+```
+
+## Preventing invalid forms from being submitted
+
+The `onChange`, `onBlur` etc... callbacks are also run when the form is submitted and the submission is blocked if the form is invalid.
+
+The form state object has a `canSubmit` flag that is false when any field is invalid and the form has been touched (`canSubmit` is true until the form has been touched, even if some fields are "technically" invalid based on their `onChange`/`onBlur` props).
+
+You can subscribe to it via `form.Subscribe` and use the value in order to, for example, disable the submit button when the form is invalid (in practice, disabled buttons are not accessible, use `aria-disabled` instead).
+
+```tsx
+const form = createForm(() => ({/* ... */}))
+
+return (
+ /* ... */
+
+ // Dynamic submit button
+ ({
+ canSubmit: state.canSubmit,
+ isSubmitting: state.isSubmitting,
+ })}
+ children={(state) => (
+
+ )}
+ />
+)
+```