Form Block
Dynamic forms powered by the @payloadcms/plugin-form-builder plugin. Forms are defined in the CMS and fetched via GraphQL — no code changes
needed to add or update fields.
Subscription Form
Contact Form
How it works
1. Define in Payload
Create a Form document in the CMS. Add fields (text, email, select, checkbox, etc.) and set the confirmation type.
2. Add to a page
Add a FormBlock to any page layout in Payload and select the form. The GraphQL query
fetches all field definitions at build time.
3. Renders & submits
FormBlock.tsx iterates the field array, renders each input, validates on submit, and
POSTs to /api/form-submissions.
Supported field types
TextField TextareaField EmailField NumberField SelectField CheckboxField MessageField Column widths
Each field's width (0–100) maps to a 12-column grid: 100 → full row, 50 → half, 33 → third,
25 → quarter. Fields sit inside a grid-cols-12 container so multiple narrow fields line up side-by-side.
Key files
src/components/Forms/FormBlock.tsx — dynamic field renderer, validation, submit handler
src/components/Forms/Input.tsx — Input, Select, TextArea primitives
src/hooks/useFormSubmit.ts — submitForm(formId, data) utility
src/hooks/useForm.ts — reusable form state & validation hook
src/components/blocks/FormBlock.astro — Astro wrapper (client:load)
src/utils/getPageBySlug.graphql.ts — GraphQL fragment for all field types
Endpoint
Submissions are sent to Payload's built-in FormSubmissions collection via submitForm() in src/hooks/useFormSubmit.ts. The form document ID comes from the GraphQL response — no hardcoding
required.
POST ${PUBLIC_PAYLOAD_API}/api/form-submissions
Content-Type: application/json
{
"form": "64a1f2e3b4c5d6e7f8a9b0c1", // Payload form document ID
"submissionData": [
{ "field": "firstName", "value": "Jane" },
{ "field": "lastName", "value": "Smith" },
{ "field": "email", "value": "jane@example.com" },
{ "field": "subject", "value": "support" },
{ "field": "message", "value": "Hello, I need help with..." },
{ "field": "consent", "value": "true" }
]
} PUBLIC_PAYLOAD_API is read from the environment. Payload validates the form ID and stores each submissionData entry as a field/value pair.
Confirmation
Message (inline)
// In Payload CMS → Forms → your form → Confirmation
confirmationType: "message"
confirmationMessage: "<h3>Thank you!</h3><p>We'll be in touch shortly.</p>"
// Rendered by FormBlock after a successful submission:
// - Replaces the form with the confirmationMessage_html content
// - No page reload required Redirect
// In Payload CMS → Forms → your form → Confirmation
confirmationType: "redirect"
redirect: { url: "/thank-you" }
// FormBlock behaviour:
// - On success, calls: window.location.href = form.redirect.url
// - Works with any internal path or external URL