Email Forms

ConvertForm — dynamic field definitions, anti-spam protection, and the submission flow.

Basic Usage

The simplest email capture form:

::convert-form{location="hero"}
::

This renders a single email field with a "Get Access" button. On submit, the email is delivered via webhook and the visitor is redirected to /success.

Props

PropTypeDefaultDescription
fieldsFieldDef[][{ name: 'email', type: 'email', ... }]Form field definitions
locationstringrequiredLocation identifier for tracking
submitLabelstring'Get Access'Submit button text
notestringSmall text below the form
layout'stacked' | 'horizontal''stacked'Form layout direction
successRedirectstringCustom redirect path after submission
offerSlugstringOffer identifier for tracking and redirect

Custom Fields

Define custom fields to capture more than just email:

::convert-form
---
location: apply-form
submitLabel: Apply Now
layout: stacked
fields:
  - name: name
    label: Full Name
    type: text
    placeholder: Jane Smith
    required: true
  - name: email
    label: Email
    type: email
    placeholder: [email protected]
    required: true
  - name: message
    label: Why are you interested?
    type: textarea
    placeholder: Tell us about your project...
    required: false
---
::

FieldDef Shape

FieldTypeDescription
namestringField identifier (used as form data key)
labelstringDisplay label above the input
type'text' | 'email' | 'textarea' | 'tel'Input type
placeholderstringPlaceholder text
requiredbooleanWhether the field must be filled

Layouts

Stacked (default)

Fields stack vertically. Best for multi-field forms:

::convert-form{location="apply" layout="stacked" submit-label="Apply"}
::

Horizontal

Email field and button side by side. Best for single-field capture:

::convert-form{location="hero" layout="horizontal" submit-label="Get Early Access"}
::

Anti-Spam Protection

Every form submission includes three layers of anti-spam protection, handled automatically by useFormCapture:

  1. Honeypot — A hidden field that bots fill but humans don't. If filled, the form silently redirects (bot thinks it succeeded).
  2. Time-on-form — Tracks how long the form was visible. Submissions under 2 seconds are flagged as suspicious.
  3. JS token — A crypto.randomUUID() generated on mount. Bots without JavaScript cannot produce a valid UUID.

These are sent with every submission and validated server-side. See Anti-Spam for the server-side scoring system.

Submission Flow

  1. User fills form and clicks submit
  2. Client-side validation — Dynamic Zod schema validates fields
  3. Honeypot check — If honeypot is filled, silently redirect (bot trap)
  4. Event firedform_submitted event with formData + antiSpam payload
  5. Webhook provider — Posts to /api/v1/webhook server handler
  6. Server processing — Anti-spam scoring, rate limiting, webhook delivery
  7. Success redirect — Navigate to success page
  8. On error — Toast notification + form_error event fired

Success Redirect

The redirect path is determined in this order:

  1. successRedirect prop (if set)
  2. /success?offer={offerSlug} (if offerSlug is set)
  3. /success (default)

Using in Vue Templates

<ConvertForm
  location="pricing-page"
  submit-label="Start Free Trial"
  layout="horizontal"
  offer-slug="trial"
  :fields="[
    { name: 'email', type: 'email', placeholder: '[email protected]', required: true },
  ]"
/>