Overview
Forms are first-class citizens in Domma CMS. Create forms in the admin panel, define fields with validation, and embed them in any page with a single shortcode. Submissions are stored and manageable in the admin, with optional email and webhook triggers.
Every form is powered by Domma's blueprint-driven Form Builder — the same engine used throughout the Domma framework. This means forms automatically benefit from client-side validation, reactive models, and consistent styling with zero additional configuration.
How it works
- Build — Create and configure a form in the admin panel (Admin → Forms → New Form)
- Validate — Define per-field validation rules with custom error messages
- Embed — Drop a shortcode on any page:
[form slug="contact"] - Collect — Submissions are stored and viewable in the admin, with optional trigger actions
Form Builder
The visual Form Builder lets you construct and configure forms entirely from the admin panel — no code required. Navigate to Admin → Forms → New Form to get started.
Form settings
Before adding fields, configure the top-level form properties:
| Setting | Description | Example |
|---|---|---|
| Form Name | Internal label used in the admin panel | Contact Form |
| Slug | URL-safe identifier used in the embed shortcode | contact |
| Submit Button Text | Label shown on the submit button | Send Message |
| Success Message | Message shown to the user after a successful submission | Thanks! We'll be in touch shortly. |
| Layout | Visual arrangement of fields | stacked, 2-column grid, inline |
| Wizard Mode | Split the form into multiple steps with a progress indicator | true / false |
Adding and arranging fields
- Click Add Field and choose a field type from the panel on the right
- Fill in the field label, name (used as the key in submission data), and placeholder text
- Configure validation rules and set a custom error message for each rule
- Drag fields up and down the list to reorder them — the order here matches the rendered form
- In Wizard Mode, assign each field to a Step using the step selector on the field card
Live preview
A live preview pane on the right-hand side of the builder renders the form exactly as it will appear to visitors, including validation states and the current theme. Changes are reflected in real time as you add, remove, or reorder fields.
Field Types
Domma CMS supports 15 field types covering every common input scenario. All types are natively styled to match your site's active theme.
| Type | Description | Notes |
|---|---|---|
text |
Single-line text input | Default type for general text fields |
email |
Email address with format validation | Automatically applies email pattern validation |
password |
Password input (masked) | Value is never included in plain-text email triggers |
textarea |
Multi-line text | Configurable rows; supports minLength / maxLength |
number |
Numeric input | Supports min, max, and step attributes |
select |
Single-choice dropdown | Options defined as a comma-separated list or JSON array |
multiselect |
Multiple-choice dropdown | Stored as an array in submission data |
checkbox |
Single boolean checkbox | Stored as true or false |
checkbox-group |
Multiple checkboxes from a defined option list | Selected values stored as an array |
radio |
Radio button group — pick one from several options | Rendered as styled pill-style radio buttons |
date |
Native date picker | Supports min and max date constraints |
file |
File upload | Configurable accepted types and max file size; uploads saved to media/uploads/ |
hidden |
Hidden value — not shown to the user | Static value or dynamically populated from a URL query parameter |
rating |
Star rating (1–5) | Rendered as interactive star icons; stored as an integer |
signature |
Canvas signature input | Stored as a base64-encoded PNG data URI; downloadable from the submissions panel |
Validation
Domma CMS enforces validation on both the client and server. Client-side validation provides instant feedback; server-side validation ensures data integrity even when JavaScript is bypassed or disabled.
Available validation rules
| Rule | Applies to | Description |
|---|---|---|
required |
All types | Field must have a non-empty value before the form can be submitted |
minLength |
text, textarea, password |
Value must be at least n characters long |
maxLength |
text, textarea, password |
Value must not exceed n characters |
min |
number, date |
Value must be greater than or equal to n |
max |
number, date |
Value must be less than or equal to n |
pattern |
text, email |
Value must match the supplied regular expression |
email |
email |
Value must be a syntactically valid email address |
url |
text |
Value must be a syntactically valid URL (includes protocol) |
Custom error messages
Every validation rule accepts a custom error message. Define it alongside the rule in the field configuration:
{
"name": "phone",
"type": "text",
"label": "Phone Number",
"validation": {
"required": { "value": true, "message": "Please enter your phone number." },
"pattern": {
"value": "^[\\d\\s\\+\\-\\(\\)]{7,20}$",
"message": "Please enter a valid phone number."
}
}
}
When no custom message is provided, Domma CMS falls back to sensible defaults (e.g. "This field is required", "Must be at least 8 characters").
Wizard Mode
Wizard Mode splits a long form into a series of focused steps, each with its own title and progress indicator. This significantly improves completion rates for complex forms such as booking flows, registration processes, or multi-stage surveys.
Enabling Wizard Mode
Toggle Wizard Mode in the form settings panel in the admin. The wizard property is set to true in the stored form JSON:
{
"slug": "booking",
"wizard": true,
"steps": [
{ "title": "Your Details" },
{ "title": "Choose a Date" },
{ "title": "Extras" },
{ "title": "Confirm & Submit" }
]
}
Assigning fields to steps
Each field has a stepTitle property that assigns it to a named step. In the admin builder, use the Step dropdown on each field card:
{
"name": "full_name",
"type": "text",
"label": "Full Name",
"stepTitle": "Your Details"
}
Wizard behaviour
| Feature | Behaviour |
|---|---|
| Validation per step | Each step validates before the user can advance. Invalid fields are highlighted inline. |
| Progress bar | Displays the current step number and total (e.g. "Step 2 of 4") above the active fields. |
| Back button | Available on all steps after the first. Previously entered values are preserved when navigating back. |
| Summary step | Optionally display a read-only summary of all entered values on the final step before submission. Enable with "summary": true on the last step. |
| Step skip | Steps can be marked optional and skipped via a "Skip" link. Set "optional": true on a step definition. |
Conditional Logic Engine
The Conditional Logic Engine allows fields and wizard steps to appear or disappear in real time based on values entered elsewhere in the form. Conditions are evaluated client-side as the user types — no page reload required.
Condition syntax
Each field or step accepts a showIf property containing a condition object or an array of condition objects:
{
"name": "company_name",
"type": "text",
"label": "Company Name",
"showIf": {
"field": "account_type",
"operator": "equals",
"value": "business"
}
}
Available operators
| Operator | Description | Works with |
|---|---|---|
equals |
Field value exactly matches the given value | All types |
notEquals |
Field value does not match the given value | All types |
contains |
Field value includes the given string or array element | text, multiselect, checkbox-group |
notContains |
Field value does not include the given string or array element | text, multiselect, checkbox-group |
greaterThan |
Field value is numerically greater than the given value | number, rating |
lessThan |
Field value is numerically less than the given value | number, rating |
isEmpty |
Field has no value (empty string, null, or unchecked) | All types |
isNotEmpty |
Field has any value | All types |
Multiple conditions with AND / OR
Pass an array of condition objects and set a combinator to join them:
{
"name": "discount_code",
"type": "text",
"label": "Discount Code",
"showIf": {
"combinator": "AND",
"conditions": [
{ "field": "plan", "operator": "equals", "value": "pro" },
{ "field": "referral", "operator": "isNotEmpty" }
]
}
}
Conditions also apply to wizard steps — set showIf on a step definition using the same syntax to skip entire steps when they are not relevant to the user's choices.
Submissions Management
Every form submission is automatically stored and accessible from the admin panel. Navigate to Admin → Forms → [Form Name] → Submissions to view, filter, export, and delete entries.
Submissions table
The submissions view displays entries in a sortable, searchable table. Each column corresponds to a form field, and the table supports:
- Column sorting — click any column header to sort ascending or descending
- Full-text search — filter entries across all field values
- Date range filter — narrow submissions to a specific time window
- Row detail view — click any row to see the full submission with all field values and metadata
Export
Export all visible submissions (respecting active filters) to CSV with a single click. The exported file includes a header row and all field values, including arrays (joined with a semicolon).
Deletion
Delete submissions individually using the Delete button on the row detail panel, or select multiple rows and use the Delete Selected bulk action. Deletion is permanent and cannot be undone.
Storage locations
| Mode | Location | Format |
|---|---|---|
| File-Only Mode | data/forms/{slug}-submissions.json |
JSON array — one object per submission, appended on each submit |
| Pro Mode | MongoDB collection form_submissions |
BSON documents with indexed formSlug and submittedAt fields |
Anti-Spam
Domma CMS ships with two complementary anti-spam mechanisms enabled by default. Both operate server-side and require no third-party service or CAPTCHA widget.
Honeypot field
An invisible field is injected into every rendered form. It is hidden from human visitors via CSS (display: none; visibility: hidden;) but is visible to automated bots that parse raw HTML. When the server receives a submission where the honeypot field is populated, the submission is silently rejected with a 200 OK response (to avoid revealing the mechanism to the bot).
The honeypot field name is randomised per form to prevent bots from explicitly targeting and ignoring it by name.
Rate limiting
A per-form, per-IP rate limit prevents flooding. The default limit is 5 submissions per IP address per hour. When the limit is exceeded, the server returns 429 Too Many Requests and the form displays a user-friendly message.
Configure limits per form in the form settings:
{
"slug": "contact",
"antispam": {
"honeypot": true,
"rateLimit": {
"enabled": true,
"max": 5,
"windowMinutes": 60
}
}
}
| Property | Default | Description |
|---|---|---|
honeypot |
true |
Inject and enforce the honeypot hidden field |
rateLimit.enabled |
true |
Enable per-IP rate limiting for this form |
rateLimit.max |
5 |
Maximum number of submissions allowed within the window |
rateLimit.windowMinutes |
60 |
Rolling window duration in minutes |
"honeypot": false or "rateLimit.enabled": false in form settings. Disabling both is not recommended for publicly accessible forms.
Triggers
Triggers run automatically after a form submission passes validation and is stored. Multiple triggers can be attached to a single form and they execute in parallel. Configure triggers under Admin → Forms → [Form Name] → Triggers.
Email trigger
Send a notification email to one or more addresses when a form is submitted. The email body is a template that can reference any field value using {{field.name}} placeholders.
{
"type": "email",
"to": ["admin@example.com", "support@example.com"],
"subject": "New contact form submission from {{field.full_name}}",
"body": "Name: {{field.full_name}}\nEmail: {{field.email}}\n\nMessage:\n{{field.message}}"
}
Email triggers use the SMTP credentials configured in config/site.json under the smtp key. All submission field values are available as {{field.*}} and metadata as {{meta.submittedAt}}, {{meta.ip}}, etc.
Webhook trigger
POST the submission data to an external URL as a JSON payload. Useful for integrating with CRMs, Slack, Zapier, Make, or any HTTP endpoint.
{
"type": "webhook",
"url": "https://hooks.example.com/form-submissions",
"headers": {
"Authorization": "Bearer your-token",
"X-Source": "domma-cms"
},
"fieldMap": {
"name": "field.full_name",
"email": "field.email",
"body": "field.message"
}
}
The fieldMap property is optional. When omitted, all field values are sent as-is. When provided, only the mapped fields are included in the webhook payload under the specified key names.
Action trigger Pro
Invoke a Domma CMS Action workflow with the submission data as input. Actions are server-side workflow definitions (Pro Mode only) that can orchestrate complex multi-step processes such as creating collection entries, sending personalised emails, or calling third-party APIs.
{
"type": "action",
"actionSlug": "onboard-new-user",
"inputMap": {
"userName": "field.full_name",
"userEmail": "field.email",
"plan": "field.selected_plan"
}
}
logs/triggers.log for review.
Embedding Forms
Once a form has been created in the admin panel, embed it on any Markdown page or content block using the [form] shortcode. The shortcode is replaced with a fully rendered, functional Domma form at render time.
Shortcode syntax
[form slug="contact"]
[form slug="newsletter" title="false"]
[form slug="booking" class="my-form"]
Shortcode attributes
| Attribute | Required | Default | Description |
|---|---|---|---|
slug |
Yes | — | The slug of the form to embed, as defined in the admin panel |
title |
No | "true" |
Whether to render the form name as a visible heading above the form. Set to "false" to hide it. |
class |
No | — | One or more additional CSS classes applied to the outer form wrapper for custom styling |
prefill |
No | — | Comma-separated list of field:param pairs to pre-fill from URL query parameters (e.g. "email:utm_email") |
Submission behaviour
- Submissions are handled via AJAX — the page does not reload on submit
- The success message configured in the form settings is displayed inline, replacing the form
- Validation errors and server-side errors are shown inline beneath the relevant field or at the top of the form
- A loading state is applied to the submit button during submission to prevent duplicate requests
Custom styling
Forms inherit your site's active Domma theme automatically. To apply additional styles, target the .dm-form wrapper or use the class shortcode attribute to add a custom class:
[form slug="contact" class="form-wide form-shadowed"]
/* In your custom CSS */
.form-wide { max-width: 800px; margin: 0 auto; }
.form-shadowed .dm-form-inner { box-shadow: 0 4px 24px rgba(0,0,0,0.15); border-radius: 12px; padding: 2rem; }