HHS Styleguide
← Back to site

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

Subscribe to get the latest news and updates delivered straight to your inbox.

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.tssubmitForm(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