diff --git a/docs/config.json b/docs/config.json index 6db122f6f..583217bd1 100644 --- a/docs/config.json +++ b/docs/config.json @@ -72,6 +72,10 @@ { "label": "react", "children": [ + { + "label": "Arrays", + "to": "framework/react/guides/arrays" + }, { "label": "UI Libraries", "to": "framework/react/guides/ui-libraries" @@ -89,6 +93,24 @@ "to": "framework/react/guides/debugging" } ] + }, + { + "label": "vue", + "children": [ + { + "label": "Arrays", + "to": "framework/vue/guides/arrays" + } + ] + }, + { + "label": "solid", + "children": [ + { + "label": "Arrays", + "to": "framework/solid/guides/arrays" + } + ] } ] }, @@ -185,6 +207,10 @@ "label": "Simple", "to": "framework/react/examples/simple" }, + { + "label": "Arrays", + "to": "framework/react/examples/array" + }, { "label": "Yup", "to": "framework/react/examples/yup" @@ -210,6 +236,10 @@ "label": "Simple", "to": "framework/vue/examples/simple" }, + { + "label": "Arrays", + "to": "framework/vue/examples/array" + }, { "label": "Yup", "to": "framework/vue/examples/yup" @@ -231,6 +261,10 @@ "label": "Simple", "to": "framework/solid/examples/simple" }, + { + "label": "Arrays", + "to": "framework/solid/examples/array" + }, { "label": "Yup", "to": "framework/solid/examples/yup" diff --git a/docs/framework/react/guides/arrays.md b/docs/framework/react/guides/arrays.md new file mode 100644 index 000000000..93ace71fa --- /dev/null +++ b/docs/framework/react/guides/arrays.md @@ -0,0 +1,129 @@ +--- +id: arrays +title: Arrays +--- + +TanStack Form supports arrays as values in a form, including sub-object values inside of an array. + +# Basic Usage + +To use an array, you can use `field.state.value` on an array value: + +```jsx +function App() { + const form = useForm({ + defaultValues: { + people: [], + }, + }) + + return ( + + {(field) => ( +
+ {field.state.value.map((_, i) => { + // ... + })} +
+ )} +
+ ) +} +``` + +This will generate the mapped JSX every time you run `pushValue` on `field`: + +```jsx + +``` + +Finally, you can use a subfield like so: + +```jsx + + {(subField) => ( + + subField.handleChange(e.target.value) + } + /> + )} + +``` + +## Full Example + +```jsx +function App() { + const form = useForm({ + defaultValues: { + people: [], + }, + onSubmit({ value }) { + alert(JSON.stringify(value)) + } + }) + + return ( +
+
{ + e.preventDefault() + e.stopPropagation() + void form.handleSubmit() + }} + > + + {(field) => { + return ( +
+ {field.state.value.map((_, i) => { + return ( + + {(subField) => { + return ( +
+ +
+ ) + }} +
+ ) + })} + +
+ ) + }} +
+ [state.canSubmit, state.isSubmitting]} + children={([canSubmit, isSubmitting]) => ( + + )} + /> + +
+ ) +} +``` diff --git a/docs/framework/react/guides/ssr.md b/docs/framework/react/guides/ssr.md index 5b1006df4..ac1ad25c6 100644 --- a/docs/framework/react/guides/ssr.md +++ b/docs/framework/react/guides/ssr.md @@ -98,7 +98,7 @@ const ClientComp = () => { formFactory.initialFormState ); - const { useStore, Provider, Subscribe, handleSubmit, Field } = + const { useStore, Subscribe, handleSubmit, Field } = formFactory.useForm({ transform: useTransform( (baseForm: FormApi) => mergeForm(baseForm, state), @@ -120,7 +120,6 @@ const ClientComp = () => { - Benefits of `formFactory`: Much like the useForm hook, formFactory streamlines the process of form management. It provides us with necessary functionalities such as: - `useStore`: Observes and reflects the current state of the form on the client side. - - `Provider`: Acts as a context provider for the form, ensuring state and actions are accessible throughout the component. - `Subscribe`: Enables the component to listen to form-specific events, like `canSubmit` and `isSubmitting`. - `handleSubmit`: Orchestrates the submission logic of the form. - `Field`: Manages individual form fields, adopting the `renderProps` pattern for greater flexibility. @@ -136,7 +135,6 @@ const ClientComp = () => { ... return ( -
handleSubmit()}> {formErrors.map((error) => (

{error}

@@ -181,11 +179,10 @@ const ClientComp = () => { )}
-
); }; ``` -- In our UI, implementing the form is straightforward. We encapsulate our form within a `Provider`. A notable aspect here is the integration of our server action within the `form`. For the form's `action`, we utilize the `action` obtained from `useFormState`. This setup triggers the server action upon form submission. If everything processes successfully, the action will complete without issues. Otherwise, we'll encounter an error like "Server validation: You must be at least 12 to sign up." +- In our UI, implementing the form is straightforward. A notable aspect here is the integration of our server action within the `form`. For the form's `action`, we utilize the `action` obtained from `useFormState`. This setup triggers the server action upon form submission. If everything processes successfully, the action will complete without issues. Otherwise, we'll encounter an error like "Server validation: You must be at least 12 to sign up." - You might now be wondering about client-side validation. How do we implement it? 🤔 The answer lies in the `handleSubmit` function. By assigning `handleSubmit` to the form's `onSubmit` event, we can handle client-side validation in the normal client side manner. diff --git a/docs/framework/react/guides/ui-libraries.md b/docs/framework/react/guides/ui-libraries.md index 27a2ee626..a8f55d4b2 100644 --- a/docs/framework/react/guides/ui-libraries.md +++ b/docs/framework/react/guides/ui-libraries.md @@ -27,7 +27,7 @@ import { TextInput, Checkbox } from '@mantine/core' import { useForm } from '@tanstack/react-form' export default function App() { - const { Provider, Field, handleSubmit, state } = useForm({ + const { Field, handleSubmit, state } = useForm({ defaultValues: { firstName: '', lastName: '', @@ -41,7 +41,6 @@ export default function App() { return ( <> -
{ e.preventDefault() @@ -70,7 +69,6 @@ export default function App() { )} />
-
{JSON.stringify(state.values, null, 2)}
@@ -80,7 +78,7 @@ export default function App() { ``` - Initially, we utilize the `useForm` hook from TanStack and destructure the necessary properties. This step is optional; alternatively, you could use `const form = useForm()` if preferred. TypeScript's type inference ensures a smooth experience regardless of the approach. -- Next, we encapsulate our form elements within the `Provider` component, a critical step for enabling form functionalities. The `Field` component, derived from `useForm`, accepts several properties, such as `validators`. For this demonstration, we focus on two primary properties: `name` and `children`. +- The `Field` component, derived from `useForm`, accepts several properties, such as `validators`. For this demonstration, we focus on two primary properties: `name` and `children`. - The `name` property identifies each `Field`, for instance, `firstName` in our example. - The `children` property leverages the concept of render props, allowing us to integrate components without unnecessary abstractions. - TanStack's design relies heavily on render props, providing access to `children` within the `Field` component. This approach is entirely type-safe. When integrating with Mantine components, such as `TextInput`, we selectively destructure properties like `state.value`, `handleChange`, and `handleBlur`. This selective approach is due to the slight differences in types between `TextInput` and the `field` we get in the children. diff --git a/docs/framework/react/quick-start.md b/docs/framework/react/quick-start.md index c1a7d6aa6..3ad03dd28 100644 --- a/docs/framework/react/quick-start.md +++ b/docs/framework/react/quick-start.md @@ -23,7 +23,6 @@ export default function App() { return (
-
{ e.preventDefault(); @@ -46,7 +45,6 @@ export default function App() {
- ) } diff --git a/docs/framework/react/reference/formApi.md b/docs/framework/react/reference/formApi.md index 1a966802c..3b67e9ff3 100644 --- a/docs/framework/react/reference/formApi.md +++ b/docs/framework/react/reference/formApi.md @@ -7,10 +7,6 @@ title: Form API When using `@tanstack/react-form`, the [core form API](../../reference/formApi) is extended at type level with additional methods for React-specific functionality: -- ```tsx - Provider: (props: PropsWithChildren) => JSX.Element - ``` - - React provider use to wrap your components. Reference React's [ContextProvider]("https://react.dev/reference/react/createContext#provider") - ```tsx Field: FieldComponent ``` diff --git a/docs/framework/solid/guides/arrays.md b/docs/framework/solid/guides/arrays.md new file mode 100644 index 000000000..255f06810 --- /dev/null +++ b/docs/framework/solid/guides/arrays.md @@ -0,0 +1,129 @@ +--- +id: arrays +title: Arrays +--- + +TanStack Form supports arrays as values in a form, including sub-object values inside of an array. + +# Basic Usage + +To use an array, you can use `field.state.value` on an array value in conjunction +with [`Index` from `solid-js`](https://www.solidjs.com/tutorial/flow_index): + +```jsx +function App() { + const form = createForm(() => ({ + defaultValues: { + people: [] + }, + })) + + return ( + + {(field) => ( + 0}> + {/* Do not change this to `For` or things will not work as-expected */} + + {(_, i) => ( + null // ... + )} + + + )} + + ) +} +``` + +> You must use `Index` from `solid-js` and not `For` because `For` will cause the inner components to be re-rendered +> every time the array changes. +> +> This causes the field to lose its value and therefore delete the subfield's value. + +This will generate the mapped JSX every time you run `pushValue` on `field`: + +```jsx + +``` + +Finally, you can use a subfield like so: + +```jsx + + {(subField) => ( + { + subField().handleChange(e.currentTarget.value) + }} + /> + )} + +``` + +## Full Example + +```jsx +function App() { + const form = createForm(() => ({ + defaultValues: { + people: [], + }, + onSubmit: ({ value }) => alert(JSON.stringify(value)), + })) + + return ( +
+
{ + e.preventDefault() + e.stopPropagation() + void form.handleSubmit() + }} + > + + {(field) => ( +
+ 0}> + {/* Do not change this to For or the test will fail */} + + {(_, i) => ( + + {(subField) => ( +
+ +
+ )} +
+ )} +
+
+ + +
+ )} +
+ +
+
+ ) +} +``` diff --git a/docs/framework/solid/quick-start.md b/docs/framework/solid/quick-start.md index a00a736ae..913da7377 100644 --- a/docs/framework/solid/quick-start.md +++ b/docs/framework/solid/quick-start.md @@ -22,7 +22,6 @@ function App() { return (

Simple Form Example

-
{ e.preventDefault() @@ -45,7 +44,6 @@ function App() {
- ) } diff --git a/docs/framework/vue/guides/arrays.md b/docs/framework/vue/guides/arrays.md new file mode 100644 index 000000000..f2e3b12a0 --- /dev/null +++ b/docs/framework/vue/guides/arrays.md @@ -0,0 +1,152 @@ +--- +id: arrays +title: Arrays +--- + +TanStack Form supports arrays as values in a form, including sub-object values inside of an array. + +# Basic Usage + +To use an array, you can use `field.state.value` on an array value in conjunction +with [`Index` from `solid-js`](https://www.solidjs.com/tutorial/flow_index): + +```vue + + + +``` + +This will generate the mapped slot every time you run `pushValue` on `field`: + +```vue + +``` + +Finally, you can use a subfield like so: + +```vue + + + +``` + +## Full Example + +```vue + + + +``` diff --git a/docs/framework/vue/quick-start.md b/docs/framework/vue/quick-start.md index 96740703a..5102daaad 100644 --- a/docs/framework/vue/quick-start.md +++ b/docs/framework/vue/quick-start.md @@ -3,11 +3,11 @@ id: quick-start title: Quick Start --- -> There is a bug in Vue's TypeScript support that's impacting our types that you'll likely run into: +> There is a bug in Vue's TypeScript support that's impacting our types that you'll likely run into: > > https://github.com/vuejs/language-tools/issues/3782 > -> Please give it a thumbs up, but _do not reply with comments such as "+1" or "When will this be fixed?", as such comments are unhelpful and rude_. +> Please give it a thumbs up, but _do not reply with comments such as "+1" or "When will this be fixed?", as such comments are unhelpful and rude_. The bare minimum to get started with TanStack Form is to create a form and add a field. Keep in mind that this example does not include any validation or error handling... yet. @@ -25,8 +25,6 @@ const form = useForm({ console.log(value) }, }) - -form.provideFormContext()