FormsFort

React

FormsFort React guide for simple contact forms, React Hook Form, file uploads, and captcha tokens.

React

Submit React forms without a custom backend. FormsFort keeps the FormsFort browser submission flow: send JSON for normal fields, send FormData for uploads, and render the API message returned by the public endpoint.

Simple React contact form

This mirrors the plain React browser submission pattern: prevent the browser navigation, build a payload from the form, post to the public endpoint, then reset only after a successful response.

import { useState } from "react";

export function ContactForm() {
  const [result, setResult] = useState("");

  async function onSubmit(event) {
    event.preventDefault();
    const form = event.currentTarget;
    const formData = new FormData(form);

    setResult("Sending...");

    const response = await fetch("https://api.formsfort.com/submit", {
      method: "POST",
      headers: {
        accept: "application/json",
        "content-type": "application/json",
      },
      body: JSON.stringify({
        access_key: "YOUR_ACCESS_KEY",
        subject: "New website lead",
        from_name: "Example Site",
        name: formData.get("name"),
        email: formData.get("email"),
        message: formData.get("message"),
      }),
    });

    const body = await response.json();
    setResult(body.message || (response.ok ? "Submitted." : "Submission failed."));

    if (response.ok) {
      form.reset();
    }
  }

  return (
    <form onSubmit={onSubmit}>
      <input name="name" autoComplete="name" required />
      <input name="email" type="email" autoComplete="email" required />
      <textarea name="message" required />
      <input type="checkbox" name="botcheck" hidden />
      <button type="submit">Send</button>
      <p role="status">{result}</p>
    </form>
  );
}

React Hook Form

React Hook Form is a client-side convenience layer. FormsFort receives the same field names and reserved options as a plain HTML form.

import { useState } from "react";
import { useForm } from "react-hook-form";

export function ContactForm() {
  const [result, setResult] = useState("");
  const {
    register,
    handleSubmit,
    reset,
    formState: { errors, isSubmitting },
  } = useForm({ mode: "onTouched" });

  async function onSubmit(fields) {
    setResult("Sending...");

    const response = await fetch("https://api.formsfort.com/submit", {
      method: "POST",
      headers: {
        accept: "application/json",
        "content-type": "application/json",
      },
      body: JSON.stringify({
        access_key: "YOUR_ACCESS_KEY",
        subject: "New website lead",
        from_name: "Example Site",
        ...fields,
      }),
    });

    const body = await response.json();
    setResult(body.message || (response.ok ? "Submitted." : "Submission failed."));

    if (response.ok) {
      reset();
    }
  }

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input
        {...register("name", { required: "Name is required", maxLength: 80 })}
        autoComplete="name"
      />
      {errors.name && <p>{errors.name.message}</p>}

      <input
        type="email"
        {...register("email", { required: "Email is required" })}
        autoComplete="email"
      />
      {errors.email && <p>{errors.email.message}</p>}

      <textarea {...register("message", { required: "Message is required" })} />
      {errors.message && <p>{errors.message.message}</p>}

      <input type="checkbox" {...register("botcheck")} hidden />
      <button type="submit" disabled={isSubmitting}>
        {isSubmitting ? "Sending..." : "Send"}
      </button>
      <p role="status">{result}</p>
    </form>
  );
}

File upload form

Use FormData directly for normal React forms or React Hook Form file fields. Do not set the content-type header; the browser adds the multipart boundary.

async function onSubmit(event) {
  event.preventDefault();
  const form = event.currentTarget;
  const formData = new FormData(form);

  formData.set("access_key", "YOUR_ACCESS_KEY");

  const response = await fetch("https://api.formsfort.com/submit", {
    method: "POST",
    headers: { accept: "application/json" },
    body: formData,
  });

  return response.json();
}

export function UploadForm() {
  return (
    <form onSubmit={onSubmit}>
      <input name="name" required />
      <input name="email" type="email" required />
      <input name="attachment" type="file" required />
      <button type="submit">Upload</button>
    </form>
  );
}

React Hook Form file upload

React Hook Form returns file inputs as a FileList. Append the first file manually before sending multipart FormData.

async function onSubmit(fields) {
  const formData = new FormData();
  formData.append("access_key", "YOUR_ACCESS_KEY");
  formData.append("name", fields.name);
  formData.append("email", fields.email);
  formData.append("attachment", fields.attachment[0]);

  const response = await fetch("https://api.formsfort.com/submit", {
    method: "POST",
    headers: { accept: "application/json" },
    body: formData,
  });

  return response.json();
}

Captcha token fields

Load Google reCAPTCHA v2, Google reCAPTCHA v3, hCaptcha, or Cloudflare Turnstile in the browser. Add the generated token under the matching FormsFort field name before submitting.

// Google reCAPTCHA v2
formData.set("g-recaptcha-response", recaptchaV2Token);

// Google reCAPTCHA v3
formData.set("recaptcha_response", recaptchaToken);

// hCaptcha
formData.set("h-captcha-response", hcaptchaToken);

// Cloudflare Turnstile
formData.set("cf-turnstile-response", turnstileToken);

React package

Install the FormsFort hook when you want the FormsFort React helper API instead of writing the fetch wrapper yourself. Keep the endpoint configurable until your production API domain is finalized.

pnpm add @formsfort/react react-hook-form
import { useForm } from "react-hook-form";
import useFormsFort from "@formsfort/react";

export default function ContactForm() {
  const { register, handleSubmit, reset } = useForm();
  const { submit, loading, result } = useFormsFort({
    access_key: "YOUR_ACCESS_KEY",
    endpoint: "https://api.formsfort.com/submit",
    settings: {
      from_name: "Example Site",
      subject: "New website lead",
    },
    onSuccess: () => reset(),
  });

  return (
    <form onSubmit={handleSubmit(submit)}>
      <input type="text" {...register("name", { required: true })} />
      <input type="email" {...register("email", { required: true })} />
      <textarea {...register("message", { required: true })} />
      <input type="checkbox" {...register("botcheck")} hidden />
      <button disabled={loading}>Submit</button>
      {result?.message ? <p>{result.message}</p> : null}
    </form>
  );
}

On this page