Schema
Learn how to define form schemas and infer TypeScript types from your field definitions.
Schema
A BuzzForm schema is the single source of truth for your form. It defines the fields, validation, and generates TypeScript types automatically.
Creating a Schema
Use defineSchema() to define your form:
import { defineSchema } from "@buildnbuzz/form-react";
const contactSchema = defineSchema({
fields: [
{ type: "text", name: "name", label: "Full Name", required: true },
{ type: "email", name: "email", label: "Email", required: true },
{ type: "textarea", name: "message", label: "Message" },
],
});Best Practice: Define schemas in separate files (e.g., lib/schemas/contact.ts) for reusability across forms and server actions. See File Organization below.
Type Inference
Use InferType to get TypeScript types from your schema's fields:
import { defineSchema, type InferType } from "@buildnbuzz/form-react";
const contactSchema = defineSchema({
fields: [
{ type: "text", name: "name", label: "Full Name", required: true },
{ type: "email", name: "email", label: "Email", required: true },
{ type: "textarea", name: "message", label: "Message" },
],
});
type ContactData = InferType<typeof contactSchema.fields>;
// Result: { name: string, email: string, message?: string }This is especially useful for server actions:
"use server";
import { contactSchema, type ContactData } from "@/lib/schemas/contact";
import { db } from "@/lib/db";
export async function submitContact(data: ContactData) {
// data is fully typed!
await db.contacts.create(data);
}File Organization
For production apps, organize schemas in dedicated files:
import { defineSchema, type InferType } from "@buildnbuzz/form-react";
export const contactSchema = defineSchema({
title: "Contact Form",
description: "Send us a message",
fields: [
{ type: "text", name: "name", label: "Full Name", required: true },
{ type: "email", name: "email", label: "Email", required: true },
{ type: "textarea", name: "message", label: "Message", required: true },
],
});
export type ContactData = InferType<typeof contactSchema.fields>;Then import in your components and actions:
"use client";
import { contactSchema } from "@/lib/schemas/contact";
import { Form, FormContent, FormFields, FormSubmit } from "@/components/buzzform/form";
import { submitContact } from "./actions";
export function ContactForm() {
return (
<Form schema={contactSchema} onSubmit={submitContact}>
<FormContent>
<FormFields />
<FormSubmit>Send Message</FormSubmit>
</FormContent>
</Form>
);
}Benefits of this pattern:
- ✅ Single source of truth for schema
- ✅ Reusable in forms, server actions, and API routes
- ✅ Type inference available everywhere
- ✅ Easy to maintain and update
React Overrides (UI)
When using @buildnbuzz/form-react, you can pass rich React elements (like tooltips, icons, or custom components) directly to label and description fields.
Import Source: To enable ReactNode support in your schemas, you must import defineSchema and InferType from @buildnbuzz/form-react instead of @buildnbuzz/form-core.
Using Tooltips in Labels
A common pattern is adding an info icon with a tooltip to a field label:
import { defineSchema } from "@buildnbuzz/form-react";
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
import { InfoIcon } from "lucide-react";
const schema = defineSchema({
fields: [
{
type: "password",
name: "password",
label: (
<span className="flex items-center gap-1.5">
Password
<Tooltip>
<TooltipTrigger render={<InfoIcon className="size-4 text-muted-foreground cursor-help" />} />
<TooltipContent>Must be at least 8 characters long.</TooltipContent>
</Tooltip>
</span>
),
required: true,
},
],
});Base Field Properties
Every field has these common properties:
Prop
Type
Nested Data Structures
Use group fields to create nested objects:
import { defineSchema, type InferType } from "@buildnbuzz/form-react";
const profileSchema = defineSchema({
fields: [
{ type: "text", name: "name", label: "Full Name" },
{
type: "group",
name: "address",
label: "Address",
fields: [
{ type: "text", name: "street", label: "Street" },
{ type: "text", name: "city", label: "City" },
{ type: "text", name: "zip", label: "ZIP Code" },
],
},
],
});
type ProfileData = InferType<typeof profileSchema.fields>;
// Result: { name: string, address?: { street: string, city: string, zip: string } }Array Data
Use array fields for repeatable items:
const jobSchema = defineSchema({
fields: [
{ type: "text", name: "name", label: "Name" },
{
type: "array",
name: "workHistory",
label: "Work History",
minItems: 1,
maxItems: 5,
fields: [
{ type: "text", name: "company", label: "Company" },
{ type: "text", name: "role", label: "Role" },
{ type: "text", name: "startDate", label: "Start Date" },
],
},
],
});
type JobData = InferType<typeof jobSchema.fields>;
// Result: { name: string, workHistory: Array<{ company: string, role: string, startDate: string }> }Complete Example
Here's a comprehensive schema combining all features:
import { defineSchema, type InferType } from "@buildnbuzz/form-react";
export const userProfileSchema = defineSchema({
title: "User Profile",
description: "Complete your profile information",
fields: [
// Basic fields
{ type: "text", name: "firstName", label: "First Name", required: true },
{ type: "text", name: "lastName", label: "Last Name", required: true },
{ type: "email", name: "email", label: "Email", required: true },
// Nested group
{
type: "group",
name: "address",
label: "Address",
fields: [
{ type: "text", name: "street", label: "Street" },
{ type: "text", name: "city", label: "City" },
{ type: "text", name: "country", label: "Country" },
],
},
// Array of items
{
type: "array",
name: "skills",
label: "Skills",
minItems: 1,
fields: [
{ type: "text", name: "name", label: "Skill Name" },
{
type: "select",
name: "level",
label: "Level",
options: ["Beginner", "Intermediate", "Advanced"],
},
],
},
],
});
export type UserProfileData = InferType<typeof userProfileSchema.fields>;
// {
// firstName: string,
// lastName: string,
// email: string,
// address?: { street: string, city: string, country: string },
// skills: Array<{ name: string, level: string }>
// }Related
- Quick Start — Build your first form with this schema
- Validation — Add validation rules to your schema
- Conditional Logic — Show/hide fields based on conditions
- Default Values — Set default values for fields