Forms

Add forms to any page. Write form: on its own line followed by indented YAML — sitemd renders it as an interactive form that submits via webhook.

Quick example

form:
  webhook: https://hooks.example.com/contact
  submitLabel: Send
  fields:
    - id: email
      type: email
      label: Email
      required: true
    - id: message
      type: longtext
      label: Message
      placeholder: Your message...

Forms submit a JSON payload to the webhook URL via POST. No backend needed from sitemd — bring your own endpoint (Zapier, Make, n8n, a serverless function, etc).

Field types

Short text

Single-line text input. The default type if type is omitted.

form:
  webhook: https://hooks.example.com/demo
  fields:
    - id: company
      type: shorttext
      label: Company Name
      placeholder: Acme Inc.

Long text

Multi-line textarea.

form:
  webhook: https://hooks.example.com/demo
  fields:
    - id: bio
      type: longtext
      label: Tell us about yourself
      placeholder: A few sentences...

Email

Input with built-in email validation.

form:
  webhook: https://hooks.example.com/demo
  fields:
    - id: email
      type: email
      label: Email Address
      required: true
      placeholder: you@example.com

Phone

form:
  webhook: https://hooks.example.com/demo
  fields:
    - id: phone
      type: phone
      label: Phone Number

Number

Supports min and max constraints.

form:
  webhook: https://hooks.example.com/demo
  fields:
    - id: quantity
      type: number
      label: Quantity
      min: 1
      max: 100

Date

form:
  webhook: https://hooks.example.com/demo
  fields:
    - id: startDate
      type: date
      label: Start Date

Name

Composite field that renders first and last name side by side. Submitted as { first: "...", last: "..." }.

form:
  webhook: https://hooks.example.com/demo
  fields:
    - id: fullName
      type: name
      label: Full Name
      required: true

Use name-first or name-last for standalone single-name fields.

form:
  webhook: https://hooks.example.com/demo
  fields:
    - id: plan
      type: dropdown
      label: Plan
      options:
        - Free
        - Pro
        - Enterprise

Radio

Single-select radio buttons.

form:
  webhook: https://hooks.example.com/demo
  fields:
    - id: priority
      type: radio
      label: Priority
      options:
        - Low
        - Medium
        - High

Checkbox

Multi-select checkboxes. Submitted as an array.

form:
  webhook: https://hooks.example.com/demo
  fields:
    - id: interests
      type: checkbox
      label: Interests
      options:
        - Product Updates
        - Technical Blog
        - Case Studies

Rating

Star rating (1–5). Uses your theme's accent color.

form:
  webhook: https://hooks.example.com/demo
  fields:
    - id: rating
      type: rating
      label: How would you rate us?

Country

Dropdown with ~195 countries. Countries listed in settings/forms.md under countrySortToTop appear first.

form:
  webhook: https://hooks.example.com/demo
  fields:
    - id: country
      type: country
      label: Country

Address

Composite field with street, city, state, zip, and country. Submitted as a nested object.

form:
  webhook: https://hooks.example.com/demo
  fields:
    - id: address
      type: address
      label: Mailing Address

Heading and paragraph

Display-only fields for structuring your form. Not included in the submission payload.

form:
  webhook: https://hooks.example.com/demo
  fields:
    - id: section1
      type: heading
      text: Personal Information
    - id: section1desc
      type: paragraph
      text: Fields marked with * are required.
    - id: name
      type: shorttext
      label: Your Name
      required: true

Personal Information

Fields marked with * are required.

Hidden

Not visible to the user. Useful for tracking data or passing context via URL prefill.

form:
  webhook: https://hooks.example.com/demo
  fields:
    - id: source
      type: hidden
      default: landing-page

Required agreement checkbox. The label text appears inline beside the checkbox. Always required — the form cannot be submitted without checking it.

form:
  webhook: https://hooks.example.com/demo
  fields:
    - id: terms
      type: consent
      label: I agree to the terms and conditions.

Field properties

Every field requires id and type. All other properties are optional.

Property Description
id Unique identifier. Used in the webhook payload and URL prefill.
type Field type (see above).
label Display label shown above the field.
description Help text shown below the label.
placeholder Placeholder text inside the input.
required Set to true to require this field before submission.
options List of choices for dropdown, radio, and checkbox types.
default Default value. For dropdowns/radios, pre-selects the matching option.
text Display text for heading and paragraph types.
min / max Numeric constraints for number type.
prefill Custom URL parameter name for prefilling (defaults to id).
showWhen Conditional visibility — fieldId = value or fieldId != value.
showWhenAny Show if any condition matches (OR logic). List of conditions.
showWhenAll Show if all conditions match (AND logic). List of conditions.

Form settings

Property Description
webhook URL to POST form data to (required).
submitLabel Text on the submit button. Default: "Submit".
thankYou Message shown after successful submission.
redirectUrl URL to redirect to after submission (instead of thank you message).

Conditional logic

Show or hide fields based on other field values using showWhen:

form:
  webhook: https://hooks.example.com/demo
  fields:
    - id: contactMethod
      type: dropdown
      label: Preferred Contact Method
      options:
        - Email
        - Phone
        - Mail
    - id: contactEmail
      type: email
      label: Email Address
      showWhen: contactMethod = Email
    - id: contactPhone
      type: phone
      label: Phone Number
      showWhen: contactMethod = Phone
    - id: contactAddress
      type: address
      label: Mailing Address
      showWhen: contactMethod = Mail

For complex conditions, use showWhenAny (OR) or showWhenAll (AND):

- id: urgentNote
  type: paragraph
  text: We'll prioritize your request.
  showWhenAll:
    - priority = High
    - contactMethod = Phone

Multi-page forms

Split forms into pages with optional conditional routing. Use pages instead of fields:

form:
  webhook: https://hooks.example.com/apply
  thankYou: Application received!
  submitLabel: Submit Application
  pages:
    - id: info
      title: Your Info
      fields:
        - id: name
          type: name
          label: Name
          required: true
        - id: role
          type: radio
          label: Role
          options:
            - Developer
            - Designer
      next:
        - when: role = Developer
          goto: dev
        - default: general
    - id: dev
      title: Developer Questions
      fields:
        - id: language
          type: dropdown
          label: Primary Language
          options:
            - JavaScript
            - Python
            - Rust
    - id: general
      title: General
      fields:
        - id: about
          type: longtext
          label: Tell us about yourself
          required: true

Your Info

Step 1 of 3

Pages flow sequentially by default. Add next rules to route conditionally — the first matching when condition wins, or default is used as a fallback. The last page shows the submit button.

URL prefill

Pre-populate form fields by adding query parameters to the URL. By default, the parameter name matches the field id:

https://yoursite.com/contact?email=jane@example.com&source=newsletter

Use the prefill property to map a different URL parameter to a field:

- id: email
  type: email
  label: Email
  prefill: user_email

Now ?user_email=jane@example.com fills the email field.

Answer piping

Reference field values in labels and descriptions using {{fieldId}}:

- id: name
  type: shorttext
  label: Your Name
- id: feedback
  type: longtext
  label: Thanks {{name}}, what's on your mind?

The label updates live as the user types.

Webhook payload

When a form is submitted, sitemd POSTs JSON to your webhook URL:

{
  "formId": "form-1",
  "submittedAt": "2026-03-16T14:30:00.000Z",
  "page": {
    "title": "Contact Us",
    "url": "https://yoursite.com/contact"
  },
  "fields": {
    "email": "jane@example.com",
    "message": "Hello!",
    "name": { "first": "Jane", "last": "Smith" },
    "interests": ["Product Updates", "Case Studies"],
    "rating": "4",
    "address": {
      "street": "123 Main St",
      "city": "Austin",
      "state": "TX",
      "zip": "78701",
      "country": "United States"
    }
  },
  "meta": {
    "referrer": "https://google.com",
    "userAgent": "Mozilla/5.0...",
    "locale": "en-US"
  }
}

Global settings

Configure defaults for all forms in settings/forms.md:

---
# Countries to sort to top of country dropdown
countrySortToTop:
  - United States
  - United Kingdom
  - Canada
  - Australia

# Default submit button label
submitLabel: Submit

# Default thank you message
thankYou: Thank you for your submission!

# Anti-spam honeypot field (invisible, catches bots)
honeypot: true
---

Per-form settings override these defaults.

Notes