React Contact Form

A ready-to-use React component that handles form submission with useState for state management and fetch for AJAX submission. Includes loading state, success message, and error handling. Drop it into any React or Next.js project. For a full walkthrough, see the React contact form guide.

React Contact Form preview

Template Code

HTML
import { useState } from 'react';

function ContactForm() {
  const [status, setStatus] = useState('idle'); // idle | sending | success | error

  async function handleSubmit(e) {
    e.preventDefault();
    setStatus('sending');

    const form = e.target;
    const data = new FormData(form);

    try {
      const res = await fetch(form.action, { method: 'POST', body: data });
      if (res.ok) {
        setStatus('success');
        form.reset();
      } else {
        setStatus('error');
      }
    } catch {
      setStatus('error');
    }
  }

  if (status === 'success') {
    return <p style={{ color: '#16a34a', fontWeight: 600 }}>Message sent! We'll be in touch.</p>;
  }

  return (
    <form action="https://app.formwit.com/api/s/YOUR_FORM_ID" method="POST" onSubmit={handleSubmit}>
      <label htmlFor="name">Name</label>
      <input type="text" id="name" name="name" required />

      <label htmlFor="email">Email</label>
      <input type="email" id="email" name="email" required />

      <label htmlFor="message">Message</label>
      <textarea id="message" name="message" required />

      {/* Honeypot spam protection */}
      <input type="text" name="_gotcha" style={{ display: 'none' }} tabIndex={-1} autoComplete="off" />

      <button type="submit" disabled={status === 'sending'}>
        {status === 'sending' ? 'Sending...' : 'Send Message'}
      </button>
      {status === 'error' && <p style={{ color: '#dc2626' }}>Something went wrong. Please try again.</p>}
    </form>
  );
}

export default ContactForm;

Want to customize?

Build your own form visually with our free HTML form generator.

Try the Form Generator →

Use cases

  • React single-page applications
  • Next.js static or server-rendered sites
  • React-based portfolios and landing pages
  • Modal or dialog contact forms in React apps

Customization tips

  • Add your own CSS classes or use a UI library like Tailwind, Chakra UI, or Material UI for styling
  • Add client-side validation with pattern attributes or a library like Zod
  • Convert to TypeScript by adding type annotations to the event parameter and state
  • Use useRef instead of e.target if you need to access the form outside the handler

Related guide

Want a step-by-step walkthrough? Read the full React Contact Form Guide.

Related templates

Frequently asked questions

Does this work with Next.js?

Yes. This is a client component — add "use client" at the top of the file for Next.js App Router. It works with both Pages Router and App Router.

Can I use this with TypeScript?

Yes. Type the event as React.FormEvent<HTMLFormElement> and the status state as a union type: 'idle' | 'sending' | 'success' | 'error'.

How do I add form validation?

HTML5 validation attributes (required, type="email") work out of the box. For custom validation, check field values in handleSubmit before calling fetch.

Get your form working in 30 seconds

  • No credit card required
  • Unlimited forms
  • 100 submissions/month free
Get Started Free