Skip to content

Your first form

A FormConfig is a plain object — no builder, no schema file to hand-write separately. This one has two fields and a submit button.

1. Write the config

import type { FormConfig } from "@/form-builder";

export const firstFormConfig: FormConfig = {
  id: "your-first-form",
  fields: [
    { type: "text", name: "name", label: "Name", required: true },
    { type: "email", name: "email", label: "Email", required: true },
    { type: "submit", name: "submit", text: "Submit" },
  ],
};

2. Render it

Pass the config to FormRenderer with an onSubmit. Nothing is sent anywhere by the engine itself — you own what happens with the values.

import { FormRenderer } from "@/form-builder";
import { firstFormConfig } from "./config";

export function SignupForm() {
  return (
    <FormRenderer
      config={firstFormConfig}
      onSubmit={(values) => {
        // values: { name: string; email: string }
        console.log(values);
      }}
    />
  );
}

3. Try it

This is the exact config above, rendered by the real FormRenderer — leave a field blank and submit to see validation kick in.

View config
{
  "id": "your-first-form",
  "fields": [
    {
      "type": "text",
      "name": "name",
      "label": "Name",
      "required": true
    },
    {
      "type": "email",
      "name": "email",
      "label": "Email",
      "required": true
    },
    {
      "type": "submit",
      "name": "submit",
      "text": "Submit"
    }
  ]
}

What you got for free

  • Zod validation— a schema is derived from the config (each field's required, type, and rules), never hand-duplicated in a separate schema file. The email field is checked for email format automatically.
  • Error messages — human-readable, out of the box, wired to each field via aria-describedby for screen readers. Override any of them with a messages prop on FormRenderer.
  • Grid layout — every field defaults to a full-width row in a 12-column responsive grid. Set width: "half" (or a per-breakpoint object) on a field to change that.

Conditional fields, multi-step wizards, and cross-field rules aren't covered here — see Examples for those working live. For the full list of field types, see Field types.