RenderFields
Render fields from schema — auto-rendering and custom layouts.
RenderFields
RenderFields and FieldRenderer are the low-level primitives for rendering fields from your schema.
API Reference
Prop
Type
Prop
Type
RenderFieldsProps
| Prop | Type | Description |
|---|---|---|
fields | Field[] | Fields to render |
form | FieldFormApi | TanStack form instance |
registry | FieldRegistry | Optional registry override |
renderFallback | (field) => ReactNode | Fallback for unregistered types |
basePath | string | Parent path for nested fields |
contextData | object | External data for dynamic values |
customValidators | ValidationRegistry | Custom validator registry |
derivedValidationMode | "submit" | "blur" | "change" | When to run derived validators |
FieldRendererProps
Same as RenderFieldsProps but renders a single field.
Basic Usage
RenderFields renders all fields from your schema:
import { contactSchema } from "@/lib/schemas/contact";
import { useForm } from "@buildnbuzz/form-react";
import { RenderFields } from "@buildnbuzz/form-react";
export function ContactForm() {
const form = useForm({ schema: contactSchema });
return (
<form onSubmit={form.handleSubmit}>
<RenderFields
fields={contactSchema.fields}
form={form}
/>
<button type="submit">Send Message</button>
</form>
);
}FieldRenderer
Render a single field from schema:
import { contactSchema } from "@/lib/schemas/contact";
import { useForm } from "@buildnbuzz/form-react";
import { FieldRenderer } from "@buildnbuzz/form-react";
export function ContactForm() {
const form = useForm({ schema: contactSchema });
const nameField = contactSchema.fields[0];
return (
<form onSubmit={form.handleSubmit}>
<FieldRenderer
field={nameField}
form={form}
/>
<button type="submit">Send Message</button>
</form>
);
}Custom Layouts
Use RenderFields inside custom layouts:
import { contactSchema } from "@/lib/schemas/contact";
import { useForm } from "@buildnbuzz/form-react";
import { RenderFields } from "@buildnbuzz/form-react";
export function ContactForm() {
const form = useForm({ schema: contactSchema });
return (
<div className="space-y-6">
<div className="grid grid-cols-2 gap-4">
<RenderFields
fields={contactSchema.fields.slice(0, 2)}
form={form}
/>
</div>
<RenderFields
fields={contactSchema.fields.slice(2)}
form={form}
/>
</div>
);
}Nested Field Rendering
RenderFields handles nested structures automatically:
import { userProfileSchema } from "@/lib/schemas/user-profile";
import { useForm } from "@buildnbuzz/form-react";
import { RenderFields } from "@buildnbuzz/form-react";
export function ProfileForm() {
const form = useForm({ schema: userProfileSchema });
// Renders nested fields with correct paths
<RenderFields fields={userProfileSchema.fields} form={form} />;
}Registry Override
Pass a custom registry for this render:
import { customRegistry } from "@/components/my-form/registry";
import { contactSchema } from "@/lib/schemas/contact";
import { useForm } from "@buildnbuzz/form-react";
import { RenderFields } from "@buildnbuzz/form-react";
export function ContactForm() {
const form = useForm({ schema: contactSchema });
<RenderFields
fields={contactSchema.fields}
form={form}
registry={customRegistry}
/>;
}Fallback Renderer
Render a placeholder for unregistered field types:
import { contactSchema } from "@/lib/schemas/contact";
import { useForm } from "@buildnbuzz/form-react";
import { RenderFields } from "@buildnbuzz/form-react";
export function ContactForm() {
const form = useForm({ schema: contactSchema });
<RenderFields
fields={contactSchema.fields}
form={form}
renderFallback={(field) => (
<div className="p-4 bg-muted">
Unknown field: {field.type}
</div>
)}
/>;
}Base Path
Render a subsection of nested fields:
import { userProfileSchema } from "@/lib/schemas/user-profile";
import { useForm } from "@buildnbuzz/form-react";
import { RenderFields } from "@buildnbuzz/form-react";
export function AddressForm() {
const form = useForm({ schema: userProfileSchema });
const addressField = userProfileSchema.fields.find(f => f.type === "group");
<RenderFields
fields={addressField?.fields || []}
form={form}
basePath="/address" // Resolves paths correctly
/>;
}How It Works
RenderFieldsiterates overfieldsarray- For each field, renders
FieldRenderer FieldRendererlooks up component inregistry- Data fields wrap with
<Field>for TanStack registration - Layout fields wrap with
<LayoutField>for context - Nested fields (group, array, row, collapsible, tabs) render children via
RenderFields
Special Cases
Tabs
Tabs handle their own nested rendering internally:
// TabsField component calls RenderFields per tab
// Children passed to tabs renderer are nullArrays
Arrays handle their own per-row rendering:
// ArrayField component calls RenderFields for each row
// Children passed to array renderer are null