Nesting Field Array in Child Component
Hi folks!
I'm trying to create an array field with the ability to to add items to the array. There is an example of how to do this in the docs (https://tanstack.com/form/latest/docs/framework/react/guides/arrays#full-example) but the docs always seem to assume that I'm rendering all my fields in the root form component where the useForm hook is called.
I want to render my own component for the array field, but I cannot figure out how to get access to <form.Field> from my child component.
I tried this:
But I get the following typescript error on the name prop:
Type 'string' is not assignable to type 'never'.
I've tried a few other things to try get this working and I'm kinda stuck now. I searched github issues and this discord but still have not found a definitive answer...
Is there a straightforward way to render <form.Field>
from inside child components?18 Replies
quickest-silver•2mo ago
withForm is intended to get specific form access from different places
in this case, you can use it (alongside an index property) to figure out which item section you‘re currently using
serving as namespace for the fields inside
conscious-sapphireOP•2mo ago
Thanks for your quick respone Luca! Appreciate you taking the time 🙂
Could you provide a link to an example of this? In the docs or elsewhere.
I would have thought this would be a very common pattern but I've not seen any examples that cover this use case.
quickest-silver•2mo ago
I‘m on mobile, so that‘s tough. It‘s in the form composition section
I can send a snippet of what I‘m referring to here in about 15 minutes
conscious-sapphireOP•2mo ago
Yeah, I've been reading that page but I'm still not sure exactly how to adapt the example to my use case. No worries, a snippet when you get chance would be great, thanks!
Some more context if it helps...
My form schema (reduced to the parts that are relevant) looks something like this:
I currently have a Schedule.tsx component that uses withFieldGroup* for the schedule property, and in turn, I render separate components for the timeRanges array field and the dateRanges array field. Something like this:
And then in ScheduleTimeRanges and ScheduleDateRanges I'd like to render the UI for those parts of the form.
*I'm not sure what the key differences are between withForm and withFieldGroup so I may be incorrectly using withFieldGroup
quickest-silver•2mo ago
* withForm: I want this form, and this form only. Useful for huge forms across multiple files
* withFieldGroup: I have fields that depend on other fields, but I want to reuse it. Useful for object fields with multiple subfields, or for dependent fields
so the final result will depend on what you need.
If you just want to organize your single form and don't intend to reuse these fields later:
https://stackblitz.com/edit/vitejs-vite-vmdpv51k?file=README.md here's an example for field groups and how they can be used in ways
withForm
can'tconscious-sapphireOP•2mo ago
So, using withForm, do I just use the defaultValues option to tell Form which fields the component is for?
quickest-silver•2mo ago
yeah, if you go with
withForm
, you'd always work from the top of the field values to the bottomconscious-sapphireOP•2mo ago
I'm not sure I understand what you mean. When you use withForm, do you need to set defaultValues that matches the entire form schema or can it be for a subset of fields?
In a withForm component, are you always working with the whole form schema and you use the name prop on <formField> to say which fields you want to manage?
quickest-silver•2mo ago
no,
withForm
is very strict. If it doesn't match the form hook you're using, it will throw an error.
such as validator mismatches or default values
withFieldGroup
only requires that the listed fields exist of the expected type. The form using it can then decide what fields to use at runtime
at the expense of type safety within withFieldGroup
of course
Perhaps I can phrase it differently. When you do:
It's equivalent to this:
except that instead of managing the hook in MySection
, it will use the form that's passed to it
<MySection form={form} />
should be okay, as long as formOptions
has the same schema and defaultValues between bothconscious-sapphireOP•2mo ago
Hmmm I suspect that the fact that my form schema is a discriminated union (zod v3) would potentially cause issues with using withForm (whatever I set defaultValues as won't match all union members). Do you know if this is the case?
Sorry, I might have caused your last reply to disappear. I'm new to discord. My apologies!
quickest-silver•2mo ago
though you might have to give typescript a nudge by extracting defaultValues using
const defaultValues: z.input<typeof yourSchema> = {}
conscious-sapphireOP•2mo ago
This isn't working for me unfortunately. 🙁
quickest-silver•2mo ago
which part?
conscious-sapphireOP•2mo ago
I didn't catch the first part of your last response before it got deleted (my bad!) but I tried your suggestion of setting the type of defaultValues to
z.input<typeof yourSchema>
to help it with the discriminated union, but I'm getting a typescript error on the form prop on my Schedule component.
I've forked your stackblitz example and modified it to demonstrate a minimal form with a discriminated union schema and using withForm for the form variants. It runs but typescript isn't happy with something.
https://stackblitz.com/edit/vitejs-vite-xeboxvrb?file=src%2FApp.tsxAndy Cochrane
StackBlitz
Simple tanstack form with zod discriminated union schema - StackBlitz
Next generation frontend tooling. It's fast!
conscious-sapphireOP•2mo ago
I didn't include any array fields (as per my original question) because I'm currently focusing on whether discriminated unions and withForm can play nice
quickest-silver•2mo ago
hmm, that's a bit irritating. TypeScript thinks "z.input is a union, but since it's a constant I'll just narrow it for you"
So the input is not actually applied. You can force the assignment (in a type safe way), but it's bulky:
alternatively, something we like to use at the workplace (for string unions too since they tend to suffer from this as well) is an identity function:
conscious-sapphireOP•2mo ago
Yes, a little bit frustrating but the type assertion is working for me and isn't too painful. I'm unblocked now! Thanks for your help @Luca | LeCarbonator 🙂
quickest-silver•2mo ago
Glad to hear! I was surprised by the activity on this particular topic. If you want to have a read, here's the TypeScript issue talking about it (closed as not planned) https://github.com/microsoft/TypeScript/issues/61789
GitHub
Skip assignment narrowing when declaring & initializing a variable ...
🔍 Search Terms declare, assign, declaration, assignment, narrow, narrowing, union, variable, "control flow analysis" ✅ Viability Checklist This wouldn't be a breaking change in existi...