Form Builder
An end-to-end forms platform for Payload v3. Author, validate, render, collect, aggregate, and act on forms.
@10x-media/form-builder is a complete forms stack built from Payload primitives and nothing else. Editors author forms as documents in the admin; your frontend renders them with a headless React layer; the server validates every submission from scratch; a post-submit pipeline emails, webhooks, and aggregates. Simple by default for editors, with a definition seam (defineFormField, defineValidationRule, defineAction, and friends) wherever developers need depth.
import { Form } from '@10x-media/form-builder/react'
export default async function ContactPage() {
const form = await fetchForm('contact') // a `forms` document via Payload's API
return <Form form={form} />
}What is in the box
Editors compose forms from fields authored as Payload blocks. Twelve types ship (text, textarea, email, number, date, select, checkbox, file, consent, calculation, repeater, message), all built through the same defineFormField primitive your custom types use, so nothing about the built-ins is privileged, and content fields are localized by default on hosts with Payload localization.
Authoring
- Fields: twelve built-in block types, plus your own through
defineFormField. - Validation: declarative rules with custom messages, cross-field and async server-only rules, and a Standard Schema escape hatch.
- Conditional logic: expressed in Payload's own
Whereshape, evaluated by one isomorphic engine on client and server. - Multi-step flows: a serializable step graph with conditional branching, authored by step titles with exclusive field assignment.
Frontend
<Form>: headless rendering with progressive validation, lifecycle events, accessible primitives, swappable renderers, and an optional layout grid.- Styling: CSS on stable class hooks, the shadcn registry, or your own components.
- Presentations: surface a form as a page, inline block, modal, or drawer.
- Accessibility: defaults verified by automated axe checks (jsdom and real-browser e2e); custom renderers get a documented contract to uphold.
Around the submission
- Recall and prefill: pipe earlier answers into labels and seed values from URL parameters.
- Calculations: derive totals and quiz scores through a no-eval expression engine recomputed on the server.
- Consent: captured with proof by reference and policy-version capture.
- File uploads: your own upload collection with server-enforced MIME and size limits.
- Post-submit actions: email, confirmation, signed webhook, or custom, run through Payload jobs with a bounded inline fallback.
- Polls and aggregation: a full lifecycle of close dates, gated result visibility, options resolved from host domain data, and a recorded final outcome, all rendered by
<FormResults>and a turnkey<Poll>over a gated public endpoint. - Spam protection: honeypot, per-identity rate limiting, bundled captcha adapters (Turnstile, reCAPTCHA, hCaptcha), upload-ownership scoping, and privacy-first metadata capture, on by default.
- Typed translations: every admin string follows the shared plugin pattern, with English and German built in.
The trust model
The client is never trusted. Conditions, validation rules, calculations, consent capture, and file constraints are all re-evaluated server-side on every submission; client-side evaluation exists for UX only and uses the same exported engines, so the two cannot drift.
Extending and configuring the plugin
Both plugin-managed collections (forms, form-submissions) accept an overrides option that uses explicit spreads. The submission admin view renders a formatted SubmissionAnswers component by default; the raw stored fields are hidden unless you set showSubmissionRawFields: true. See Customization for the full API.
Comparing to @payloadcms/plugin-form-builder
This plugin is a superset of Payload's own @payloadcms/plugin-form-builder. Both center on the same core idea, a forms collection editors author paired with a form-submissions collection under a public-create, logged-in-read access model (see Submit contract), but this plugin builds substantially more on top: a headless frontend renderer instead of bring-your-own, conditional logic and multi-step flows evaluated by one client/server engine, a declarative validation-rule framework beyond a bare required check, polls with extensible outcome strategies and scheduled auto-close, consent resolved live against sources you own, spam protection (honeypot, rate limiting, pluggable captcha), department-routed and multi-tenant-aware email, and typed translations with English and German built in.
One thing this plugin deliberately leaves out: payment. Native ships a payment field, priceConditions (a base price adjusted by other answers), and a handlePayment scaffold for wiring a processor. This plugin has no equivalent: the position is that form building, submissions, and notification are the scope, and commerce belongs in a dedicated payments or checkout layer, not folded into a forms plugin. A calculation field's expression engine can still derive a price number from other answers when a form only needs to show or record one; charging for it stays out of scope.
When to use it
Any Payload project that needs forms beyond a hardcoded contact form: marketing sites where editors ship new forms without deploys, quizzes and calculators, gated downloads, surveys and polls. Everything is a Payload collection underneath (forms, form-submissions, and your uploads collection), so your existing access control, hooks, and APIs apply.
Start with the quick start.