How to Create a Contact Form in React (2 Minutes)

Build a fully functional contact form with backend submission. No server code required.

The Problem

You need a contact form on your React website. Users should be able to send you messages. But you don't want to set up a backend server, write API routes, configure a database, or deal with email services.

The Solution

FormFlow provides a useFormFlow hook that handles everything: form state, validation, submission, storage, and email notifications. All in 3 lines of code.

What You'll Build

A contact form with:

  • Email field (validated)
  • Name field
  • Message textarea
  • Submit button with loading state
  • Backend submission (automatic)
  • Email notifications (automatic)
  • Spam protection (automatic)

Step 1: Install FormFlow

npm install @formflow.sh/react

Step 2: Get Your API Key

Sign up at formflow.sh and create a free API key. Free tier includes 50 submissions/month.

Add it to your .env.local:

NEXT_PUBLIC_FORMFLOW_API_KEY=ff_live_your_key_here

Step 3: Create the Form Component

Here's the complete code:

import { useFormFlow } from '@formflow.sh/react';
import { Input } from '@/components/ui/input';
import { Button } from '@/components/ui/button';
import { Label } from '@/components/ui/label';
import { Textarea } from '@/components/ui/textarea';

export function ContactForm() {
  const { register, handleSubmit, formState } = useFormFlow({
    apiKey: process.env.NEXT_PUBLIC_FORMFLOW_API_KEY,
    onSuccess: () => alert('Thanks! We\'ll get back to you soon.'),
  });

  return (
    <form onSubmit={handleSubmit} className="space-y-4 max-w-md">
      <div>
        <Label htmlFor="email">Email *</Label>
        <Input
          {...register('email')}
          id="email"
          type="email"
          placeholder="you@example.com"
          required
        />
      </div>

      <div>
        <Label htmlFor="name">Name *</Label>
        <Input
          {...register('name')}
          id="name"
          placeholder="John Doe"
          required
        />
      </div>

      <div>
        <Label htmlFor="message">Message *</Label>
        <Textarea
          {...register('message')}
          id="message"
          placeholder="How can we help you?"
          rows={5}
          required
        />
      </div>

      <Button type="submit" disabled={formState.isSubmitting}>
        {formState.isSubmitting ? 'Sending...' : 'Send Message'}
      </Button>
    </form>
  );
}

That's It!

Your contact form is complete and fully functional. Here's what happens when someone submits:

  1. Client-side validation runs (email format, required fields)
  2. Form data is sent to FormFlow backend
  3. Spam protection filters out bots
  4. Submission is stored in your dashboard
  5. You receive an email notification
  6. User sees success message

Customization Options

Add More Fields

Add any fields you want:

<div>
  <Label htmlFor="phone">Phone (optional)</Label>
  <Input {...register('phone')} id="phone" type="tel" />
</div>

<div>
  <Label htmlFor="company">Company (optional)</Label>
  <Input {...register('company')} id="company" />
</div>

Add Validation

Use react-hook-form validation:

<Input
  {...register('email', {
    required: 'Email is required',
    pattern: {
      value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i,
      message: 'Invalid email address',
    },
  })}
  id="email"
  type="email"
/>
{formState.errors.email && (
  <p className="text-red-500 text-sm">
    {formState.errors.email.message}
  </p>
)}

Customize Success Action

Instead of alert, redirect or show custom message:

const { register, handleSubmit, formState } = useFormFlow({
  apiKey: process.env.NEXT_PUBLIC_FORMFLOW_API_KEY,
  onSuccess: () => {
    router.push('/thank-you');
    // or show custom success component
  },
  onError: (error) => {
    console.error('Failed to send:', error);
    // show error message to user
  },
});

View Submissions

All submissions appear in your FormFlow dashboard at formflow.sh/dashboard. You can:

  • View all submissions
  • Export to CSV
  • Set up email notifications
  • Configure webhooks

Works With Any UI Library

The example above uses shadcn/ui, but FormFlow works with any UI library:

Material-UI

import TextField from '@mui/material/TextField';
import Button from '@mui/material/Button';

<TextField {...register('email')} label="Email" type="email" />
<Button type="submit">Send</Button>

Chakra UI

import { Input, Button } from '@chakra-ui/react';

<Input {...register('email')} placeholder="Email" />
<Button type="submit">Send</Button>

Native HTML

<input {...register('email')} type="email" required />
<button type="submit">Send</button>

Why FormFlow?

No Backend Code

With traditional solutions, you'd need to:

  • Create an API endpoint (/api/contact)
  • Set up a database
  • Configure email service (SendGrid, etc.)
  • Handle validation and spam protection
  • Deploy and maintain the backend

FormFlow handles all of this automatically.

Production Ready

FormFlow includes everything you need:

  • ✓ Rate limiting
  • ✓ Spam protection (honeypot)
  • ✓ Email notifications
  • ✓ Data storage
  • ✓ CSV export
  • ✓ Webhook support

Next Steps

Related Resources

Ready to add a contact form to your React app?

Get started in 2 minutes. No credit card required.

How to Create a Contact Form in React (2 Minutes) | FormFlow Blog | FormFlow