BuzzForm
BuzzFormDocs

Migration Guide

Upgrading from @buildnbuzz/buzzform to @buildnbuzz/form-core + @buildnbuzz/form-react.

Migration Guide

@buildnbuzz/buzzform is deprecated. All new development should use @buildnbuzz/form-core and @buildnbuzz/form-react.

This guide covers migrating from the deprecated @buildnbuzz/buzzform package to the new two-package architecture.

Overview of Changes

Old (buzzform)New (form-core + form-react)
Single packageTwo packages: core + React adapter
createSchema()Plain FormSchema object or defineSchema()
InferType<typeof schema>InferType<typeof schema.fields>
useRhf() / zodResolveruseForm() with built-in validation
BuzzFormProvider<FormProvider registry={...}>
validate: (value) => stringvalidate: { onBlur: { checks: [...] } }
disabled: (data) => booleandisabled: { $data: "/field", eq: value }
minRows / maxRowsminItems / maxItems
dependencies arrayAutomatic via $data references

Step 1: Update Dependencies

Uninstall the old package and install the new ones:

# Remove old package
pnpm remove @buildnbuzz/buzzform

# Install new packages
pnpm add @buildnbuzz/form-core @buildnbuzz/form-react

# Peer dependencies (if not already installed)
pnpm add @tanstack/react-form @tanstack/form-core

Step 2: Replace Schema Creation

Before:

import { createSchema } from "@buildnbuzz/buzzform";

const schema = createSchema([
  { type: "text", name: "name", label: "Name", required: true },
  { type: "email", name: "email", label: "Email", required: true },
]);

After:

import { defineSchema } from "@buildnbuzz/form-core";

const schema = defineSchema({
  fields: [
    { type: "text", name: "name", label: "Name", required: true },
    { type: "email", name: "email", label: "Email", required: true },
  ],
});

Step 3: Update Type Inference

Before:

import { InferType } from "@buildnbuzz/buzzform";

type FormData = InferType<typeof schema>;

After:

import { InferType } from "@buildnbuzz/form-core";

type FormData = InferType<typeof schema.fields>;
// Note: .fields is now required

Step 4: Replace useRhf with useForm

Before:

import { useRhf, zodResolver } from "@buildnbuzz/buzzform";
import { z } from "zod";

const formSchema = z.object({
  name: z.string().min(1),
  email: z.string().email(),
});

const form = useRhf({
  schema: formSchema,
  resolver: zodResolver(formSchema),
});

After:

import { useForm } from "@buildnbuzz/form-react";
import { defineSchema } from "@buildnbuzz/form-core";

const schema = defineSchema({
  fields: [
    { type: "text", name: "name", label: "Name", required: true },
    { type: "email", name: "email", label: "Email", required: true },
  ],
});

const form = useForm({
  schema,
  // Validation is built-in, no resolver needed
});

Step 5: Update Provider Setup

Before:

import { BuzzFormProvider } from "@buildnbuzz/buzzform";

<BuzzFormProvider>
  <App />
</BuzzFormProvider>

After:

import { FormProvider } from "@buildnbuzz/form-react";
import { registry } from "@/components/buzzform/registry";

<FormProvider registry={registry}>
  <App />
</FormProvider>

The new provider requires an explicit FieldRegistry. If you installed with @buzzform/all, use the pre-built registry.

Step 6: Migrate Validation

Before:

{
  type: "text",
  name: "username",
  label: "Username",
  validate: (value, context) => {
    if (value.length < 3) {
      return "Username must be at least 3 characters";
    }
    return true;
  },
}

After:

{
  type: "text",
  name: "username",
  label: "Username",
  validate: {
    onBlur: {
      checks: [
        {
          type: "minLength",
          message: "Username must be at least 3 characters",
          args: { min: 3 },
        },
      ],
    },
  },
}

Custom Validators

Before:

validate: async (value) => {
  const available = await checkUsername(value);
  return available ? true : "Username is taken";
}

After:

import { defineValidators } from "@buildnbuzz/form-core";

// Register custom validator using defineValidators
const customValidators = defineValidators({
  usernameAvailable: async (value: unknown) => {
    if (typeof value !== "string") return false;
    
    const available = await checkUsername(value);
    return available ? true : "Username is taken";
  },
});

const form = useForm({
  schema,
  customValidators,
});

// In schema
{
  type: "text",
  name: "username",
  validate: {
    onBlur: {
      checks: [
        {
          type: "usernameAvailable",
          message: "Username is already taken",
        },
      ],
    },
  },
}

Step 7: Migrate Conditional Logic

Before:

// Function-based conditions
{
  type: "text",
  name: "teamName",
  label: "Team Name",
  condition: (data) => data.role === "Manager",
  disabled: (data) => !data.country,
}

After:

// Declarative AST conditions
{
  type: "text",
  name: "teamName",
  label: "Team Name",
  condition: { $data: "/role", eq: "Manager" },
  disabled: { $data: "/country", eq: "" },
}

Complex Conditions

Before:

condition: (data) => data.role === "Manager" && data.department === "Engineering"

After:

condition: [
  { $data: "/role", eq: "Manager" },
  { $data: "/department", eq: "Engineering" },
]
// Array = implicit AND

Or:

condition: {
  $and: [
    { $data: "/role", eq: "Manager" },
    { $data: "/department", eq: "Engineering" },
  ],
}

Step 8: Update Field Properties

Array Fields

Before:

{
  type: "array",
  name: "items",
  minRows: 1,
  maxRows: 10,
}

After:

{
  type: "array",
  name: "items",
  minItems: 1,
  maxItems: 10,
}

Remove Dependencies

Before:

{
  type: "select",
  name: "state",
  options: states,
  dependencies: ["country"],
  disabled: (data) => !data.country,
}

After:

{
  type: "select",
  name: "state",
  options: states,
  // dependencies removed - automatic via $data
  disabled: { $data: "/country", eq: "" },
}

Complete Example

Before (Old API)

"use client";

import { createSchema, InferType, useRhf } from "@buildnbuzz/buzzform";
import { BuzzFormProvider } from "@buildnbuzz/buzzform";

const schema = createSchema([
  { type: "text", name: "name", label: "Name", required: true },
  { type: "email", name: "email", label: "Email", required: true },
  {
    type: "text",
    name: "teamName",
    label: "Team Name",
    condition: (data) => data.role === "Manager",
  },
]);

type FormData = InferType<typeof schema>;

export function ContactForm() {
  const form = useRhf({
    schema,
    onSubmit: (data) => {
      console.log(data);
    },
  });

  return (
    <form onSubmit={form.handleSubmit}>
      {/* fields */}
    </form>
  );
}

After (New API)

"use client";

import { defineSchema, type InferType } from "@buildnbuzz/form-core";
import { Form, FormContent, FormFields, FormSubmit } from "@/components/buzzform/form";

const schema = defineSchema({
  fields: [
    { type: "text", name: "name", label: "Name", required: true },
    { type: "email", name: "email", label: "Email", required: true },
    {
      type: "text",
      name: "teamName",
      label: "Team Name",
      condition: { $data: "/role", eq: "Manager" },
    },
  ],
});

type FormData = InferType<typeof schema.fields>;

export function ContactForm() {
  return (
    <Form
      schema={schema}
      onSubmit={({ value }) => {
        console.log(value);
      }}
    >
      <FormContent>
        <FormFields />
        <FormSubmit>Submit</FormSubmit>
      </FormContent>
    </Form>
  );
}

Breaking Changes Summary

  1. Package splitbuzzformform-core + form-react
  2. Schema creationcreateSchema() removed, use defineSchema() or plain object
  3. Type inferenceInferType<typeof schema>InferType<typeof schema.fields>
  4. Form hookuseRhf()useForm() with built-in validation
  5. ProviderBuzzFormProvider<FormProvider registry={...}>
  6. Validation — Function-based → ValidationConfig with checks arrays
  7. Conditions — Function-based → VisibilityCondition AST
  8. Array propsminRows/maxRowsminItems/maxItems
  9. Dependenciesdependencies array removed, automatic via $data

On this page