Skip to content
FormSubmit

Framer

How to connect a Framer site to a form backend

Use a Framer code component to send form submissions to FormSubmit — emails, Slack, Sheets and webhooks without Framer form limits.

1 min readUpdated Sep 28, 2026

To connect a Framer site to FormSubmit, add a code component that posts FormData to your endpoint. Framer code components are React, so the same pattern as any React form applies.

Steps

  1. Create a FormSubmit form and copy the endpoint.
  2. In Framer, open Assets → Code → New component and name it ContactForm.
  3. Replace the file contents with the component below and update ENDPOINT.
  4. Drag it onto your page, size it, and publish.
ContactForm.tsx
// Framer: Assets → Code → New component, paste this, then drag it onto the canvas.
import { useState, type FormEvent } from "react";

const ENDPOINT = "https://formsubmit.app/f/YOUR_FORM_ID";

export default function ContactForm() {
  const [status, setStatus] = useState<"idle" | "sending" | "success" | "error">("idle");
  const [error, setError] = useState("");
  const [renderedAt] = useState(() => Date.now());

  async function onSubmit(e: FormEvent<HTMLFormElement>) {
    e.preventDefault();
    setStatus("sending");
    const data = new FormData(e.currentTarget);
    data.set("_ts", String(renderedAt)); // helps FormSubmit's time-based spam check
    try {
      const res = await fetch(ENDPOINT, {
        method: "POST",
        body: data,
        headers: { Accept: "application/json" },
      });
      const json = await res.json();
      if (!res.ok || !json.ok) throw new Error(json.error?.message ?? "Something went wrong");
      setStatus("success");
      e.currentTarget.reset();
    } catch (err) {
      setError((err as Error).message);
      setStatus("error");
    }
  }

  if (status === "success") {
    return <p className="text-green-700">Thanks! We'll be in touch soon.</p>;
  }

  return (
    <form onSubmit={onSubmit} className="mx-auto max-w-lg space-y-5">
      <div className="space-y-1.5">
        <label htmlFor="fs-name" className="block text-sm font-medium text-gray-900">Name</label>
        <input id="fs-name" type="text" name="name" placeholder="Jane Doe" required className="block w-full rounded-lg border border-gray-300 px-3 py-2 text-sm shadow-sm focus:border-indigo-500 focus:outline-none focus:ring-2 focus:ring-indigo-500/20" />
      </div>
      <div className="space-y-1.5">
        <label htmlFor="fs-email" className="block text-sm font-medium text-gray-900">Email</label>
        <input id="fs-email" type="email" name="email" placeholder="jane@example.com" required className="block w-full rounded-lg border border-gray-300 px-3 py-2 text-sm shadow-sm focus:border-indigo-500 focus:outline-none focus:ring-2 focus:ring-indigo-500/20" />
      </div>
      <div className="space-y-1.5">
        <label htmlFor="fs-message" className="block text-sm font-medium text-gray-900">Message</label>
        <textarea id="fs-message" name="message" rows={5} placeholder="How can we help?" required className="block w-full rounded-lg border border-gray-300 px-3 py-2 text-sm shadow-sm focus:border-indigo-500 focus:outline-none focus:ring-2 focus:ring-indigo-500/20"></textarea>
      </div>
      {/* Honeypot: bots fill this in, humans never see it */}
      <input type="text" name="_gotcha" tabIndex={-1} autoComplete="off" style={{ display: "none" }} />
      {status === "error" && <p className="text-sm text-red-600">{error}</p>}
      <button type="submit" disabled={status === "sending"} className="inline-flex w-full items-center justify-center rounded-lg bg-gray-900 px-4 py-2.5 text-sm font-medium text-white hover:bg-gray-800 disabled:opacity-50">
        {status === "sending" ? "Sending…" : "Send"}
      </button>
    </form>
  );
}

Styling

The generated component uses Tailwind-style class names; Framer doesn't ship Tailwind, so replace them with inline style objects or a small <style> tag, or build the form visually in the form generator and choose the plain HTML + CSS export as a starting point.

Protect the form

Add your *.framer.app preview domain and custom domain to the allowlist.

Frequently asked questions

Can I style the component in Framer?

The component uses regular class names and inline styles you can edit in code. You can also expose Framer property controls for colours and labels.

Keep reading

Your form backend is 60 seconds away

Sign in with Google, create a form, paste the endpoint. Free forever for small sites — no credit card.