Basic Contact Form

A simple contact form with name, email, and message fields.

Complete Example

tsx
import { useState } from 'react';
import { FormBuilder, FormViewer, FormSchema } from '@formmorf/builder';
import '@formmorf/builder/dist/style.css';

// Define the contact form schema
const contactFormSchema: FormSchema = {
  id: 'contact-form',
  title: 'Contact Us',
  description: 'We would love to hear from you',
  fields: [
    {
      id: '1',
      type: 'text',
      name: 'fullName',
      label: 'Full Name',
      placeholder: 'John Doe',
      required: true,
      validation: {
        minLength: 2,
        customMessage: 'Please enter your full name'
      }
    },
    {
      id: '2',
      type: 'email',
      name: 'email',
      label: 'Email Address',
      placeholder: 'john@example.com',
      required: true,
      helpText: 'We will never share your email'
    },
    {
      id: '3',
      type: 'phone',
      name: 'phone',
      label: 'Phone Number',
      placeholder: '+1 (555) 000-0000',
      required: false
    },
    {
      id: '4',
      type: 'select',
      name: 'subject',
      label: 'Subject',
      required: true,
      options: [
        { label: 'General Inquiry', value: 'general' },
        { label: 'Technical Support', value: 'support' },
        { label: 'Billing Question', value: 'billing' },
        { label: 'Partnership', value: 'partnership' }
      ]
    },
    {
      id: '5',
      type: 'textarea',
      name: 'message',
      label: 'Message',
      placeholder: 'Tell us how we can help you...',
      required: true,
      validation: {
        minLength: 10,
        maxLength: 500,
        customMessage: 'Message must be between 10 and 500 characters'
      }
    }
  ]
};

function ContactPage() {
  const [submitted, setSubmitted] = useState(false);

  const handleSubmit = async (data: Record<string, any>) => {
    console.log('Form data:', data);

    // Send to backend
    try {
      const response = await fetch('/api/contact', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(data)
      });

      if (response.ok) {
        setSubmitted(true);
        // Show success message or redirect
        alert('Thank you for contacting us!');
      }
    } catch (error) {
      console.error('Submission error:', error);
      alert('Failed to submit form');
    }
  };

  return (
    <div className="container mx-auto max-w-2xl py-8">
      <h1 className="mb-8 text-3xl font-bold">Contact Us</h1>

      {submitted ? (
        <div className="rounded-lg border bg-green-50 p-6">
          <h2 className="text-xl font-semibold text-green-800">
            Thank You!
          </h2>
          <p className="mt-2 text-green-700">
            We have received your message and will get back to you soon.
          </p>
        </div>
      ) : (
        <FormViewer
          schema={contactFormSchema}
          onSubmit={handleSubmit}
        />
      )}
    </div>
  );
}

export default ContactPage;

Schema Breakdown

Let's break down the form schema:

Full Name Field

  • • Type: text
  • • Required with minimum 2 characters
  • • Custom validation message

Email Field

  • • Type: email
  • • Automatic email format validation
  • • Help text shown below field

Phone Field

  • • Type: phone
  • • Optional field (required: false)
  • • Formatted phone input

Subject Field

  • • Type: select
  • • Dropdown with predefined options
  • • Required selection

Message Field

  • • Type: textarea
  • • Min/max length validation (10-500 chars)
  • • Multi-line text input

Backend Integration

Example API endpoint for handling form submissions:

tsx
// pages/api/contact.ts
import type { NextApiRequest, NextApiResponse } from 'next';

export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse
) {
  if (req.method !== 'POST') {
    return res.status(405).json({ error: 'Method not allowed' });
  }

  const { fullName, email, phone, subject, message } = req.body;

  // Validate data
  if (!fullName || !email || !subject || !message) {
    return res.status(400).json({ error: 'Missing required fields' });
  }

  try {
    // Send email notification
    await sendEmail({
      to: 'contact@example.com',
      subject: `Contact Form: ${subject}`,
      html: `
        <h2>New Contact Form Submission</h2>
        <p><strong>Name:</strong> ${fullName}</p>
        <p><strong>Email:</strong> ${email}</p>
        <p><strong>Phone:</strong> ${phone || 'Not provided'}</p>
        <p><strong>Subject:</strong> ${subject}</p>
        <p><strong>Message:</strong></p>
        <p>${message}</p>
      `
    });

    // Save to database (optional)
    await db.contacts.create({
      data: { fullName, email, phone, subject, message }
    });

    return res.status(200).json({ success: true });
  } catch (error) {
    console.error('Contact form error:', error);
    return res.status(500).json({ error: 'Failed to process submission' });
  }
}

💡 Best Practices

  • • Always validate on both client and server side
  • • Show clear success/error messages to users
  • • Add loading states during submission
  • • Consider adding reCAPTCHA for spam protection
  • • Send confirmation emails to users