Forms & Form Builder
Create forms with the visual Form Builder and connect them to custom blocks by storing the form's ID in a block field.
Overview
Cmssy has a built-in Form Builder that lets you create forms visually and connect them to any custom block. Forms handle validation, submissions, email notifications, and webhooks — so your blocks only need to render the UI.
The system has two parts:
- Form Builder (Dashboard > Forms) — define fields, validation, and actions
- A
formIdfield on your block — stores which form the block should render
Creating a Form
1. Open the Form Builder
Go to Dashboard → Forms → Create Form. Give it a name and slug (e.g. contact-form).
2. Add Fields
Each field has:
| Property | Description |
|---|---|
| name | Unique field key (e.g. email, message) |
| type | text, email, textarea, number, phone, url, date, select, multiselect, checkbox, radio, file, hidden |
| label | Display label (multilingual) |
| placeholder | Placeholder text (multilingual) |
| validation | required, minLength, maxLength, minValue, maxValue, pattern, customMessage |
| width | full, half, or third — controls field width in the form grid |
| options | For select, multiselect, radio — array of { value, label } |
| order | Display order |
3. Configure Settings
| Setting | Description |
|---|---|
| Action Type | contact (email + save), newsletter (subscribe), login, register, custom (webhook) |
| Email Recipients | List of emails that receive form notifications |
| Webhook URL | For custom action — POST submission data to an external endpoint |
| Success Message | Shown after successful submission (multilingual) |
| Error Message | Shown on failure (multilingual) |
| Submit Button Label | Button text (multilingual) |
| Save Submissions | Store submissions in the database (default: true) |
| Send Email Notification | Email recipients on each submission (default: true) |
| Enable Captcha | Spam protection |
| Require Login | Only logged-in users can submit |
4. Publish
Set status to Published. Copy its form ID — you'll reference it from your block.
Using Forms in Custom Blocks
Referencing a Form
Add a formId field to your block schema and paste the published form's ID into it from the editor:
// blocks/contact/block.ts
import type { ComponentType } from "react";
import { defineBlock, fields } from "@cmssy/react";
import Component from "./src";
export const contactBlock = defineBlock({
type: "contact",
label: "Contact",
component: Component as unknown as ComponentType<{ content: Record<string, unknown> }>,
props: {
formId: fields.singleLine({ label: "Form", helperText: "Paste the form ID from the Form Builder" }),
submitLoadingText: fields.singleLine({ label: "Loading Text", defaultValue: "Sending..." }),
successHeading: fields.singleLine({ label: "Success Heading", defaultValue: "Message Sent!" }),
},
});Rendering the Form
The SDK automatically resolves any form referenced by a block's formId and injects the definition into the block context as context.forms[formId] — no fetching needed:
// blocks/contact/src/Contact.tsx
export default function Contact({ content, context }) {
const { formId } = content;
const formDef = formId ? context?.forms?.[formId] ?? null : null;
// formDef.fields - array of field definitions
// formDef.settings - submit label, messages, action type
// ...render the fields
}Submitting the Form
Submit from a server action using client.queryScoped with the exported SUBMIT_FORM_MUTATION. It validates fields, saves the submission, sends email notifications, calls any webhook, and returns a success/error response:
// blocks/contact/src/actions.ts
"use server";
import { createCmssyClient, SUBMIT_FORM_MUTATION, type CmssyFormSubmitResponse } from "@cmssy/react";
const client = createCmssyClient({
apiUrl: process.env.CMSSY_API_URL!,
workspaceSlug: process.env.CMSSY_WORKSPACE_SLUG!,
});
export async function submitForm(formId: string, data: Record<string, string>) {
const res = await client.queryScoped<{ submitForm: CmssyFormSubmitResponse }>(
SUBMIT_FORM_MUTATION,
{ formId, input: { data } },
{ workspaceId: process.env.CMSSY_WORKSPACE_ID },
);
return res.submitForm; // { success, message }
}Reference Form Blocks
Cmssy doesn't ship blocks — in the headless model you build blocks in your own repo with the SDK. These are common form blocks you can implement as reference patterns, each wiring a Form Builder form (its actionType) to a block you render:
| Block | Form Action | Description |
|---|---|---|
| Contact | contact | Contact form with info cards and quote |
| Newsletter | newsletter | Email signup form |
| Login | login | Authentication form |
| Register | register | User registration |
| Forgot Password | login | Password reset request |
Each defines the form server-side in the Form Builder and renders it in a block via a formId field — the dev owns the markup. See Member Authentication for the auth flows.
Form Submissions
Viewing Submissions
Go to Dashboard → Forms → [Your Form] → Submissions. Each submission shows:
- All field values
- Status (
pending,processed,spam,archived) - IP address, user agent, referrer
- Timestamp
- Email/webhook delivery status
Submission Lifecycle
- User submits form on your published site
- Server validates fields and checks rate limits
- Submission is saved with status
pending - Email notification sent to recipients (if enabled)
- Webhook called (if configured)
- Status updated to
processed
Spam Protection
Forms include built-in rate limiting:
- Per-IP rate limit per form
- Optional captcha support
- Honeypot fields can be added as
hiddenfield type
Action Types Reference
contact
Saves submission + sends email to configured recipients. The default for most forms.
newsletter
Subscribes the email field to the workspace newsletter list.
login / register
Handles authentication. These are special action types used by the auth form blocks you build (see Member Authentication).
custom
POSTs the submission data as JSON to your webhook URL. Useful for integrating with external services (Zapier, Slack, CRMs, etc.).
Tips
- Always publish your form before referencing it — draft forms can't be resolved
- Use
halfandthirdwidths to create multi-column form layouts (e.g. first name + last name side by side) - Multilingual labels — form fields support per-language labels and placeholders, matching the site's language system
- Test submissions are saved like real ones — delete them from the Submissions tab when done
- Webhook debugging — check the submission's
webhookResponsefield for response details from your endpoint