AutoFormAutoForm
React Hook Form

Migration from V1

This guide will help you migrate from the old, pure shadcn/ui component to the new AutoForm library.

V1 refers to the original shadcn/ui auto-form component. V2 is the current @autoform/* package ecosystem.

Please note that the new library does not have full feature partity with the old one - specifically, it does not support the following features (yet):

  • Dependencies between fields
  • Declaring custom field components inline. This should instead be done using the formComponents prop of the AutoForm component and using it with fieldConfig in schema.

But the new AutoForm library has a lot of new features, such as:

  • Support for any array, not just arrays of objects
  • Support for other schema libraries, not just zod
  • Cleaner, in-schema fieldConfig definition
  • Cleaner shadcn/ui components, as they are now just wrappers around the AutoForm library
  • Support for customizing the form components and UI components on a per-form basis, not just globally

Remove existing shadcn/ui component

First, remove the components/ui/auto-form folder from your project.

Install AutoForm

To install AutoForm, run the following command:

npx shadcn@latest add https://raw.githubusercontent.com/vantezzen/autoform/refs/heads/main/packages/shadcn/registry/autoform-rhf.json
npm install @autoform/zod react-hook-form @hookform/resolvers

Update form components

The new AutoForm uses the autoform folder for a more consistent naming schema.

You also need to wrap your schema in a ZodProvider and pass it to the AutoForm component. Instead of passing the AutoFormSubmit component as a child of AutoForm, you can simply use the withSubmit prop.

- import AutoForm, { AutoFormSubmit } from "@/components/ui/auto-form";
+ import { AutoForm } from "@/components/ui/autoform/react-hook-form";
+ import { ZodProvider } from "@autoform/zod";

const mySchema = z.object({
  // ...
});

+ const schemaProvider = new ZodProvider(mySchema);

function MyForm() {
  return (
    <AutoForm
-     formSchema={mySchema}
+     schema={schemaProvider}
      onSubmit={(data) => {
        console.log(data);
      }}
-     fieldConfig={...}
+     withSubmit
    >
-     <AutoFormSubmit />
    </AutoForm>
  );
}

Update fieldConfig

Instead of passing the fieldConfig prop to the AutoForm component, you can now define the field config directly in the schema using the fieldConfig function.

import * as z from "zod";
+ import { fieldConfig } from "@autoform/zod";
+ import { FieldTypes } from "@/components/ui/autoform/react-hook-form";

const formSchema = z.object({
  password: z
    .string()
    .min(8, {
      message: "Please use a secure password.",
    })
+   .check(
+     fieldConfig<React.ReactNode, FieldTypes>({
+       description: "We recommend to use a strong password.",
+       inputProps: {
+         type: "password",
+       },
+     })
+   ),
});

Update callbacks

If you are only using onSubmit, existing two-argument handlers still work. onSubmit can now also receive the submit event as a third argument: (data, form, event).

If you need to access form methods outside onSubmit, prefer creating an external form control with createFormControl and passing it to formControl.

import * as React from "react";
import { createFormControl } from "react-hook-form";

function MyForm() {
  const { formControl, reset } = React.useMemo(() => createFormControl(), []);

  return (
    <>
      <AutoForm formControl={formControl} schema={schemaProvider} />
      <button onClick={() => reset()}>Reset</button>
    </>
  );
}

Update custom components

If you are using custom parent components or custom field components, you need to update your code to use the new formComponents and uiComponents props and the fieldWrapper field config. Object, array, and array element wrappers can also be customized per field with objectWrapper, arrayWrapper, and arrayElementWrapper.

const schema = z.object({
  username: z.string().check(
    fieldConfig({
      fieldWrapper: (props) => (
        <div>
          <label>{props.label}</label>
          {props.children}
        </div>
      ),
    }),
  ),
});
const schemaProvider = new ZodProvider(schema);

<AutoForm
  schema={schemaProvider}
  formComponents={{
    custom: ({ id, inputProps }) => {
      const { field } = useController({ name: id });

      return (
        <div>
          <input
            id={id}
            type="text"
            className="bg-red-400 rounded-lg p-4"
            {...inputProps}
            {...field}
            value={field.value ?? ""}
          />
        </div>
      );
    },
  }}
/>;

Custom field components no longer receive value or onChange directly. Use useController from react-hook-form to get the field bindings, and treat inputProps as the props configured with fieldConfig.inputProps.

const { field, fieldState } = useController({ name: id });

If you previously imported buildZodFieldConfig, buildYupFieldConfig, or buildJoiFieldConfig from @autoform/react, replace those helpers with fieldConfig from the matching schema package:

import { fieldConfig } from "@autoform/zod";

On this page