Skip to content

Contact Form

Build a complete contact form that validates input, sanitizes data, saves submissions to the database, and sends an email notification.

Database Table

Create a table called submissions with these columns:

ColumnTypeDescription
idint (auto)Primary key
namevarchar(255)Submitter's name
emailvarchar(255)Submitter's email
subjectvarchar(255)Message subject
messagetextMessage body
created_atdatetimeSubmission timestamp

UI Layout

Build this widget tree:

Form Container
  ├── Heading ("Contact Us")
  ├── Text Input (name: "name", label: "Your Name", required: true)
  ├── Text Input (name: "email", label: "Email Address", required: true)
  ├── Text Input (name: "subject", label: "Subject", required: true)
  ├── Textarea (name: "message", label: "Message", required: true)
  └── Submit Button ("Send Message")

Action Pipeline (onSubmit)

Configure the Form Container's onSubmit action with this pipeline:

Context
  → Rate Limit (maxRequests: 3, windowSeconds: 60, scope: "ip")
    → Validate
      → Sanitize
        → Set Field (created_at = now())
          → Save Row (tableId: submissions)
            → Send Email
              → Output

Node Configurations

Rate Limit:

maxRequests: 3
windowSeconds: 60
scope: "ip"

Validate (rules):

json
[
  { "field": "name", "rule": "required" },
  { "field": "name", "rule": "min_length", "value": "2" },
  { "field": "email", "rule": "required" },
  { "field": "email", "rule": "email" },
  { "field": "subject", "rule": "required" },
  { "field": "message", "rule": "required" },
  { "field": "message", "rule": "min_length", "value": "10" }
]

Sanitize (fields):

json
[
  { "field": "name", "method": "strip_tags" },
  { "field": "name", "method": "trim" },
  { "field": "email", "method": "sanitize_email" },
  { "field": "subject", "method": "strip_tags" },
  { "field": "subject", "method": "trim" },
  { "field": "message", "method": "esc_html" },
  { "field": "message", "method": "trim" }
]

Set Field:

fieldName: "created_at"
expression: "now()"

Save Row:

tableId: (your submissions table ID)

Send Email:

to: "admin@example.com"
subject: "Contact Form: `{ {row.subject}}`"
body: "Name: `{ {row.name}}`\nEmail: `{ {row.email}}`\nSubject: `{ {row.subject}}`\n\nMessage:\n`{ {row.message}}`"

How It Works

  1. The user fills out the form and clicks "Send Message".
  2. Context collects all form field values into a single object.
  3. Rate Limit blocks spam (max 3 submissions per minute per IP).
  4. Validate checks all fields. If validation fails, error messages are displayed next to the form fields.
  5. Sanitize cleans the data (strips HTML tags, trims whitespace, validates email format).
  6. Set Field adds the current timestamp.
  7. Save Row inserts the submission into the database.
  8. Send Email notifies the site admin.
  9. Output returns the result to the frontend (success or error).

Variations

Add a confirmation email to the submitter

Add a second Send Email node after the first:

to: "`{ {row.email}}`"
subject: "We received your message"
body: "Hi `{ {row.name}}`,\n\nThank you for contacting us. We will respond within 24 hours.\n\nBest regards,\nThe Team"

Add a honey pot field for bot prevention

Add a hidden Text Input (name: "website", label: "Website"). In the Validate rules, add:

json
{ "field": "website", "rule": "max_length", "value": "0" }

Bots fill in all fields; real users leave the hidden field empty.

TIP

Always include Rate Limit and Validate in public-facing form pipelines. Without them, anyone can spam your database and email by calling the REST endpoint directly.