MyCuppa
Components/Organisms/Contact Form

Contact Form

Feature-rich contact form with validation, file uploads, and email integration

Platforms:
webiosandroid
Version 1.0.0

Contact Form

A comprehensive contact form component with built-in validation, file uploads, spam protection, and email service integration.

Features

  • Field Validation: Email, phone, required fields with real-time feedback
  • File Uploads: Attach documents, images with size/type validation
  • Spam Protection: reCAPTCHA, honeypot, rate limiting
  • Email Integration: SendGrid, Resend, SMTP support
  • Auto-save Drafts: Save form data to prevent data loss
  • Multi-step Forms: Break long forms into steps
  • Accessibility: WCAG 2.1 AA compliant
  • Custom Fields: Add dynamic fields based on inquiry type

Installation

pnpm add @mycuppa/contact-form

Basic Usage

import { ContactForm } from '@mycuppa/contact-form'

export function SimpleContact() {
  const handleSubmit = async (data) => {
    console.log('Form submitted:', data)
    // Send to your backend or email service
  }

  return (
    <ContactForm
      onSubmit={handleSubmit}
      fields={['name', 'email', 'message']}
    />
  )
}

With All Fields

import { ContactForm, FormField } from '@mycuppa/contact-form'

const fields: FormField[] = [
  { name: 'name', type: 'text', label: 'Full Name', required: true },
  { name: 'email', type: 'email', label: 'Email Address', required: true },
  { name: 'phone', type: 'tel', label: 'Phone Number' },
  {
    name: 'inquiryType',
    type: 'select',
    label: 'Inquiry Type',
    options: [
      { value: 'general', label: 'General Question' },
      { value: 'support', label: 'Technical Support' },
      { value: 'sales', label: 'Sales Inquiry' },
    ],
  },
  { name: 'company', type: 'text', label: 'Company' },
  { name: 'message', type: 'textarea', label: 'Message', required: true, rows: 5 },
  { name: 'attachment', type: 'file', label: 'Attach File', accept: '.pdf,.doc,.docx' },
]

export function ContactUs() {
  const handleSubmit = async (data) => {
    const response = await fetch('/api/contact', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(data),
    })

    if (response.ok) {
      alert('Message sent successfully!')
    }
  }

  return (
    <div className="max-w-2xl mx-auto p-6">
      <h2 className="text-2xl font-bold mb-6">Get in Touch</h2>
      <ContactForm
        fields={fields}
        onSubmit={handleSubmit}
        submitButtonText="Send Message"
        successMessage="Thank you! We'll get back to you soon."
      />
    </div>
  )
}

With Email Integration (SendGrid)

import { ContactForm } from '@mycuppa/contact-form'
import { sendEmail } from '@/lib/email'

export function ContactWithEmail() {
  const handleSubmit = async (data) => {
    await sendEmail({
      to: 'support@example.com',
      from: data.email,
      subject: `New Contact Form: ${data.inquiryType}`,
      html: `
        <h2>New Contact Form Submission</h2>
        <p><strong>Name:</strong> ${data.name}</p>
        <p><strong>Email:</strong> ${data.email}</p>
        <p><strong>Phone:</strong> ${data.phone || 'N/A'}</p>
        <p><strong>Message:</strong></p>
        <p>${data.message}</p>
      `,
    })
  }

  return <ContactForm onSubmit={handleSubmit} />
}

Multi-Step Form

import { ContactForm, FormStep } from '@mycuppa/contact-form'

const steps: FormStep[] = [
  {
    title: 'Your Information',
    fields: ['name', 'email', 'phone'],
  },
  {
    title: 'Your Inquiry',
    fields: ['inquiryType', 'company', 'message'],
  },
  {
    title: 'Review',
    fields: [], // Review step
  },
]

export function MultiStepContact() {
  return (
    <ContactForm
      steps={steps}
      showProgress
      onSubmit={handleSubmit}
    />
  )
}

With reCAPTCHA

import { ContactForm } from '@mycuppa/contact-form'

export function ProtectedContact() {
  return (
    <ContactForm
      onSubmit={handleSubmit}
      recaptcha={{
        siteKey: process.env.NEXT_PUBLIC_RECAPTCHA_SITE_KEY,
        version: 'v3',
      }}
    />
  )
}

Props

| Prop | Type | Default | Description | |------|------|---------|-------------| | fields | FormField[] \| string[] | Required | Form fields to display | | steps | FormStep[] | - | Multi-step configuration | | onSubmit | (data: FormData) => Promise<void> | Required | Submit handler | | submitButtonText | string | 'Submit' | Submit button label | | successMessage | string | 'Thank you for your message!' | Success message | | errorMessage | string | 'Something went wrong. Please try again.' | Error message | | recaptcha | RecaptchaConfig | - | reCAPTCHA configuration | | showProgress | boolean | false | Show progress indicator | | autoSave | boolean | false | Auto-save form data | | resetOnSuccess | boolean | true | Reset form after submit |

Field Types

FormField Object

interface FormField {
  name: string
  type: 'text' | 'email' | 'tel' | 'textarea' | 'select' | 'file' | 'checkbox'
  label: string
  placeholder?: string
  required?: boolean
  validation?: (value: any) => string | undefined
  options?: Array<{ value: string; label: string }> // For select
  accept?: string // For file input
  rows?: number // For textarea
}

Validation

Built-in validators:

import { validators } from '@mycuppa/contact-form'

const fields = [
  {
    name: 'email',
    type: 'email',
    label: 'Email',
    validation: validators.email,
  },
  {
    name: 'phone',
    type: 'tel',
    label: 'Phone',
    validation: validators.phone,
  },
  {
    name: 'website',
    type: 'text',
    label: 'Website',
    validation: validators.url,
  },
]

Custom validation:

const fields = [
  {
    name: 'code',
    type: 'text',
    label: 'Promo Code',
    validation: (value) => {
      if (value && value.length !== 8) {
        return 'Code must be 8 characters'
      }
    },
  },
]

Backend Example (Next.js)

// app/api/contact/route.ts
import { NextRequest, NextResponse } from 'next/server'
import { sendEmail } from '@/lib/email'

export async function POST(request: NextRequest) {
  const data = await request.json()

  // Validate
  if (!data.name || !data.email || !data.message) {
    return NextResponse.json(
      { error: 'Missing required fields' },
      { status: 400 }
    )
  }

  // Send email
  await sendEmail({
    to: 'support@example.com',
    from: data.email,
    subject: `Contact Form: ${data.name}`,
    html: `
      <h2>New Contact Form Submission</h2>
      <p><strong>Name:</strong> ${data.name}</p>
      <p><strong>Email:</strong> ${data.email}</p>
      <p><strong>Message:</strong></p>
      <p>${data.message}</p>
    `,
  })

  return NextResponse.json({ success: true })
}

Styling

<ContactForm
  className="contact-form"
  style={{
    '--input-border': '#e5e7eb',
    '--input-focus': '#3b82f6',
    '--button-bg': '#3b82f6',
  }}
/>

Related