T
TanStack5mo ago
xenial-black

Form composition create reusable component using withForm

I want to create an Address Component that can be included in other forms. This component should just extend the existing form values with the address values:
const formSchema = z.object({
newField: z.string().min(1),
// Nest the address fields under an 'address' key
...AddressSchema.shape,
});
type AllFormFields = z.infer<typeof formSchema>;

export default function Home() {
const form = useAppForm({
defaultValues: {} as AllFormFields,
validators: {
onBlur: formSchema,
},
onSubmit: async ({ value }) => {
console.log(value);
},
});
return (
<div className="grid grid-rows-[20px_1fr_20px] items-center justify-items-center min-h-screen p-8 pb-20 gap-16 sm:p-20 font-[family-name:var(--font-geist-sans)]">
<main className="flex flex-col gap-[32px] row-start-2 items-center sm:items-start">
<form
onSubmit={(e) => {
e.preventDefault();
e.stopPropagation();
form.handleSubmit();
}}
>
<form.AppField
name="newField"
children={(field) => (
<field.TextField label="some textfield" />
)}
/>
<AddressForm form={form}></AddressForm>
<form.AppForm>
<form.SubmitButton>Senden</form.SubmitButton>
</form.AppForm>
</form>
</main>
</div>
);
}
const formSchema = z.object({
newField: z.string().min(1),
// Nest the address fields under an 'address' key
...AddressSchema.shape,
});
type AllFormFields = z.infer<typeof formSchema>;

export default function Home() {
const form = useAppForm({
defaultValues: {} as AllFormFields,
validators: {
onBlur: formSchema,
},
onSubmit: async ({ value }) => {
console.log(value);
},
});
return (
<div className="grid grid-rows-[20px_1fr_20px] items-center justify-items-center min-h-screen p-8 pb-20 gap-16 sm:p-20 font-[family-name:var(--font-geist-sans)]">
<main className="flex flex-col gap-[32px] row-start-2 items-center sm:items-start">
<form
onSubmit={(e) => {
e.preventDefault();
e.stopPropagation();
form.handleSubmit();
}}
>
<form.AppField
name="newField"
children={(field) => (
<field.TextField label="some textfield" />
)}
/>
<AddressForm form={form}></AddressForm>
<form.AppForm>
<form.SubmitButton>Senden</form.SubmitButton>
</form.AppForm>
</form>
</main>
</div>
);
}
However I cannot get the form to work as expected. The Fields render correctly but when I fill in the inputs, the SubmitButton does not think the input is valid (SubmitButton is the same as in docs).
export const AddressForm = withForm({
defaultValues: {} as Address,
render: function Render({ form }) {/*formfields*/}
export const AddressForm = withForm({
defaultValues: {} as Address,
render: function Render({ form }) {/*formfields*/}
5 Replies
fair-rose
fair-rose5mo ago
withForm requires the values and validators to align with the form you want to use it in so extending any form that satisfies withForm is not supported (yet)
xenial-black
xenial-blackOP5mo ago
is there any other way to create such a component then?
fair-rose
fair-rose5mo ago
you sacrifice some type safety, but at the moment, this is a solution you can go for https://github.com/TanStack/form/discussions/1200#discussioncomment-12363833
GitHub
Compose forms with nested form structure · TanStack form · Discus...
The new createFormHook looks great but it appears that it only works when there's a shared data structure between the child and parent forms. The use case where this applies is when you have a ...
fair-rose
fair-rose5mo ago
either that or you create a composite field (a field that manages state as AddressObject instead of multiple values)
xenial-black
xenial-blackOP5mo ago
Thank you very much 👍 This should be a reasonable workaround for now.

Did you find this page helpful?