Auto Form

Component creates form based on Zod schemas & react-hook-form with validation

Preview

Usage

import { AutoForm } from "@vitnode/core/components/form/auto-form";
import { AutoFormCheckbox } from "@vitnode/core/components/form/fields/checkbox";
import { AutoFormInput } from "@vitnode/core/components/form/fields/input";
import { AutoFormSelect } from "@vitnode/core/components/form/fields/select";
import { AutoFormTextarea } from "@vitnode/core/components/form/fields/textarea";
import { z } from "zod";
const formSchema = z.object({
  username: z.string().min(3, "Username must be at least 3 characters"),
  email: z
    .email("Please enter a valid email address")
    .describe("We'll use this email to contact you. (from zod schema)"),
  user_type: z.enum(["admin", "editor", "viewer"]),
  accept_terms: z.boolean().refine(val => val, {
    message: "You must accept the terms and conditions",
  }),
  description: z.string().min(10, "Description must be at least 10 characters"),
});
<AutoForm
  fields={[
    {
      id: "username",
      component: props => (
        <AutoFormInput
          {...props}
          description="This is the username for your application. It should be unique and not shared with anyone."
          label="Username"
        />
      ),
    },
    {
      id: "email",
      component: props => <AutoFormInput {...props} label="Email Address" />,
    },
    {
      id: "user_type",
      component: props => (
        <AutoFormSelect
          {...props}
          description="Select the type of user."
          label="User Type"
          labels={[
            { value: "admin", label: "Admin" },
            { value: "editor", label: "Editor" },
            { value: "viewer", label: "Viewer" },
          ]}
        />
      ),
    },
    {
      id: "accept_terms",
      component: props => (
        <AutoFormCheckbox
          {...props}
          label="I accept the terms and conditions"
        />
      ),
    },
    {
      id: "description",
      component: props => (
        <AutoFormTextarea
          {...props}
          description="Write a short description of your application."
          label="Description"
          placeholder="My application is..."
        />
      ),
    },
  ]}
  formSchema={formSchema}
/>

Zod Schema Configuration

Auto Form is deeply integrated with Zod, supporting Zod validators. HTML input attributes are automatically applied based on your schema constraints.

Required vs Optional Fields

By default, all fields are required. Make a field optional using the optional method:

const formSchema = z.object({
  username: z.string(), // Required field
  bio: z.string().optional(), // Optional field
});

Labels

Set field labels using the label property in the field definition:

{
  id: 'username',
  component: props => (
    <AutoFormInput {...props} label="Username" />
  ),
}

Right Labels

You can also add a label on the right side of the field using the labelRight property:

{
  id: 'username',
  component: props => (
    <AutoFormInput {...props} label="Username" labelRight="Required" />
  ),
}

Descriptions

Add descriptions to fields using the description property:

{
  id: 'username',
  component: props => (
    <AutoFormInput
      {...props}
      label="Username"
      description="This is the username for your application."
    />
  ),
}

or using the describe method in Zod:

const formSchema = z.object({
  username: z.string().describe("This is the username for your application."),
});

Default Values

Set default values for fields using the default method:

const formSchema = z.object({
  username: z.string().default("user123"),
  role: z.enum(["user", "admin"]).default("user"),
});

Advanced Validation

Auto Form supports all Zod validators:

const formSchema = z.object({
  username: z.string().min(3).max(20),
  email: z.email(),
  age: z.number().min(18).max(120),
  password: z
    .string()
    .min(8)
    .refine(val => /[A-Z]/.test(val), {
      message: "Password must contain at least one uppercase letter",
    }),
});

Custom Fields

This documentation is under construction! 🚧

We're working hard to bring you the best documentation experience.

Form Submission

To activate submit button and handle form submission with the onSubmit callback:

<AutoForm
  fields={[
    {
      id: "username",
      component: props => (
        <AutoFormInput
          {...props}
          description="This is the username for your application."
          label="Username"
        />
      ),
    },
  ]}
  formSchema={formSchema}
  onSubmit={values => {
    // Handle form submission
  }}
/>

Accessing the Form Instance

The onSubmit callback provides access to the React Hook Form instance as a second parameter:

<AutoForm
  fields={
    [
      /* ...field definitions */
    ]
  }
  formSchema={formSchema}
  onSubmit={(values, form) => {
    // Access form methods
    form.setError("username", {
      type: "manual",
      message: "Username already taken",
    });
  }}
/>

You can also define the submission handler separately:

import type { AutoFormOnSubmit } from "@vitnode/core/components/form/auto-form";
const onSubmit: AutoFormOnSubmit<typeof formSchema> = async (values, form) => {
  try {
    await saveData(values);
    toast.success("Form submitted successfully");
  } catch (error) {
    form.setError("root", {
      type: "manual",
      message: "Failed to submit form",
    });
  }
};

// Then in your component
<AutoForm
  fields={
    [
      /* ...field definitions */
    ]
  }
  formSchema={formSchema}
  onSubmit={onSubmit}
/>;

Customizing the Submit Button

Customize the submit button using the submitButtonProps:

<AutoForm
  fields={
    [
      /* ...field definitions */
    ]
  }
  formSchema={formSchema}
  submitButtonProps={{
    variant: "outline",
    size: "lg",
    children: "Save Changes",
    className: "w-full mt-4",
  }}
  onSubmit={values => {
    console.log("Form submitted", values);
  }}
/>

Form Layout and Styling

You can control the form layout using standard CSS techniques:

<AutoForm
  className="grid grid-cols-1 gap-4 md:grid-cols-2"
  fields={
    [
      /* ...field definitions */
    ]
  }
  formSchema={formSchema}
/>
Auto Form - VitNode