Templates / React

React contact form with validation

SPAs and component libraries that still want a native POST path.

Live preview

Preview only — does not submit. Copy the code block below for the real snippet.

Copy-paste code

ContactForm.tsx
import { FormEvent, useState } from "react";

export function ContactForm() {
  const [error, setError] = useState<string | null>(null);

  function onSubmit(e: FormEvent<HTMLFormElement>) {
    const data = new FormData(e.currentTarget);
    const email = String(data.get("email") ?? "");
    if (!email.includes("@")) {
      e.preventDefault();
      setError("Enter a valid email.");
    }
  }

  return (
    <form action="https://formheron.com/f/YOUR_KEY" method="POST" onSubmit={onSubmit}>
      <input type="email" name="email" required placeholder="Email" />
      <textarea name="message" required placeholder="Message" />
      <input type="text" name="_hp" tabIndex={-1} autoComplete="off" aria-hidden="true"
        style={{ position: "absolute", left: "-9999px" }} />
      {error ? <p role="alert">{error}</p> : null}
      <button type="submit">Send</button>
    </form>
  );
}

What to change

  • Replace YOUR_KEY.
  • Swap inline styles for your CSS modules or Tailwind.
  • For SPA-only UX, switch to fetch() and handle JSON error codes.

Related templates