Framer Contact Form - Connect FormWit to Framer

Last updated: March 2026

Framer does not have built-in form handling. If you want a Framer contact form that sends emails and stores submissions, you need an external form backend. This guide shows how to embed an HTML contact form in Framer and connect it to FormWit so every submission reaches your inbox and dashboard.

How it works

Framer sites are published as static pages. They do not run server-side code, so there is no way to process form submissions natively. A form backend fills that gap. You embed a standard HTML form inside a Framer code component or HTML embed, point the form's action to a FormWit endpoint, and FormWit handles the rest: spam filtering, data storage, and email delivery.

The flow:

  1. A visitor fills out the contact form on your Framer site
  2. The browser sends the form data to your FormWit endpoint
  3. FormWit validates the data, checks for spam, and stores the submission
  4. You receive an email notification and can view submissions in your dashboard
  5. The visitor is redirected to a thank-you page or sees a success message

Set up a contact form in Framer

Step 1: Create a FormWit account

Go to app.formwit.com/auth/signup and create a free account. No credit card required. Click Create Form, name it (e.g., "Framer Contact Form"), and copy the endpoint URL. It looks like https://app.formwit.com/api/s/YOUR_FORM_ID.

Step 2: Add a code component in Framer

Framer supports custom code components that let you write HTML, CSS, and JavaScript inside your design. This is how you embed a form.

  1. Open your Framer project in the editor
  2. In the left panel, click the Assets tab (the grid icon)
  3. Click Code at the top, then click the + button to create a new code component
  4. Name it "ContactForm"
  5. Replace the default code with the form component below
import { useState } from "react"

export default function ContactForm() {
  const [status, setStatus] = useState("idle")

  const FORM_URL = "https://app.formwit.com/api/s/YOUR_FORM_ID"

  async function handleSubmit(e) {
    e.preventDefault()
    setStatus("sending")

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

    try {
      const response = await fetch(FORM_URL, {
        method: "POST",
        body: data,
      })

      if (response.ok) {
        setStatus("success")
        form.reset()
      } else {
        setStatus("error")
      }
    } catch {
      setStatus("error")
    }
  }

  return (
    <form onSubmit={handleSubmit} style={formStyle}>
      <div style={fieldStyle}>
        <label htmlFor="name" style={labelStyle}>Name</label>
        <input
          type="text"
          id="name"
          name="name"
          required
          style={inputStyle}
        />
      </div>

      <div style={fieldStyle}>
        <label htmlFor="email" style={labelStyle}>Email</label>
        <input
          type="email"
          id="email"
          name="email"
          required
          style={inputStyle}
        />
      </div>

      <div style={fieldStyle}>
        <label htmlFor="message" style={labelStyle}>Message</label>
        <textarea
          id="message"
          name="message"
          rows={5}
          required
          style={{ ...inputStyle, resize: "vertical" }}
        />
      </div>

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

      <button
        type="submit"
        disabled={status === "sending"}
        style={buttonStyle}
      >
        {status === "sending" ? "Sending..." : "Send Message"}
      </button>

      {status === "success" && (
        <p style={{ color: "#16a34a", marginTop: 8 }}>
          Message sent successfully!
        </p>
      )}
      {status === "error" && (
        <p style={{ color: "#dc2626", marginTop: 8 }}>
          Something went wrong. Please try again.
        </p>
      )}
    </form>
  )
}

const formStyle = {
  width: "100%",
  maxWidth: 500,
  fontFamily: "Inter, system-ui, sans-serif",
}

const fieldStyle = {
  marginBottom: 16,
}

const labelStyle = {
  display: "block",
  marginBottom: 4,
  fontSize: 14,
  fontWeight: 600,
  color: "#374151",
}

const inputStyle = {
  width: "100%",
  padding: "10px 12px",
  border: "1px solid #d1d5db",
  borderRadius: 6,
  fontSize: 14,
  color: "#111827",
  outline: "none",
  boxSizing: "border-box",
}

const buttonStyle = {
  background: "#4f46e5",
  color: "white",
  padding: "10px 24px",
  border: "none",
  borderRadius: 6,
  fontSize: 14,
  fontWeight: 600,
  cursor: "pointer",
}

Replace YOUR_FORM_ID with the endpoint ID from your FormWit dashboard. Framer code components use React syntax, so the form is written as a React functional component with inline styles. The hidden _gotcha field is a honeypot that catches spam bots.

Step 3: Place the component on your page

After saving the code component:

  1. Go to the page where you want the contact form
  2. Open the Assets panel and find your "ContactForm" component under Code
  3. Drag it onto the canvas
  4. Resize the component frame to fit your layout

The form will render live in the Framer editor. You can position it alongside other Framer elements, wrap it in a section, and adjust the frame dimensions to match your design.

Step 4: Publish and test

Click Publish in Framer to deploy your site. Visit your published site, fill out the form, and click "Send Message." Check your FormWit dashboard to see the submission and your email inbox for the notification.

Alternative: HTML embed approach

If you prefer not to write a code component, you can use Framer's HTML embed element. This is simpler but gives you less control over the form's appearance.

  1. Add an HTML Embed element from the Insert menu (or press / and search for "embed")
  2. Paste a standard HTML form into the embed:
<form action="https://app.formwit.com/api/s/YOUR_FORM_ID" method="POST">
  <div style="margin-bottom:12px">
    <label for="name" style="display:block;margin-bottom:4px;font-weight:600;font-size:14px">Name</label>
    <input type="text" id="name" name="name" required
      style="width:100%;padding:8px 12px;border:1px solid #d1d5db;border-radius:6px;font-size:14px;box-sizing:border-box" />
  </div>

  <div style="margin-bottom:12px">
    <label for="email" style="display:block;margin-bottom:4px;font-weight:600;font-size:14px">Email</label>
    <input type="email" id="email" name="email" required
      style="width:100%;padding:8px 12px;border:1px solid #d1d5db;border-radius:6px;font-size:14px;box-sizing:border-box" />
  </div>

  <div style="margin-bottom:12px">
    <label for="message" style="display:block;margin-bottom:4px;font-weight:600;font-size:14px">Message</label>
    <textarea id="message" name="message" rows="5" required
      style="width:100%;padding:8px 12px;border:1px solid #d1d5db;border-radius:6px;font-size:14px;box-sizing:border-box;resize:vertical"></textarea>
  </div>

  <input type="text" name="_gotcha" style="display:none" tabindex="-1" autocomplete="off" />

  <button type="submit"
    style="background:#4f46e5;color:white;padding:10px 24px;border:none;border-radius:6px;font-weight:600;cursor:pointer">
    Send Message
  </button>
</form>

The HTML embed approach uses a standard form POST. After submission, FormWit will redirect the visitor. Add a hidden redirect_to field to control where they go:

<input type="hidden" name="redirect_to" value="https://yoursite.com/thank-you" />

The code component approach (Step 2) is better for most projects because it handles submission inline without a page redirect and shows success/error states.

Styling tips for Framer

Framer code components use inline styles (JavaScript objects) instead of CSS classes. Here are some tips to match your form's look to your Framer design:

  • Match your brand colors. Update buttonStyle.background to match your site's primary color. Update labelStyle.color and inputStyle.border to match your text and border colors.
  • Match your font. Change formStyle.fontFamily to match the font stack used in your Framer project.
  • Full-width layout. Remove maxWidth from formStyle if you want the form to fill its parent container.
  • Focus states. Framer code components support the onFocus and onBlur events. Use useState to toggle a focused style on inputs for a polished interaction.

Adding extra fields

You can add any HTML input to the form. FormWit accepts all named fields. For example, to add a phone number and subject line:

<div style={fieldStyle}>
  <label htmlFor="phone" style={labelStyle}>Phone (optional)</label>
  <input
    type="tel"
    id="phone"
    name="phone"
    style={inputStyle}
  />
</div>

<div style={fieldStyle}>
  <label htmlFor="subject" style={labelStyle}>Subject</label>
  <select id="subject" name="subject" style={inputStyle}>
    <option value="">Select a topic</option>
    <option value="general">General Inquiry</option>
    <option value="support">Support</option>
    <option value="billing">Billing</option>
  </select>
</div>

Every field with a name attribute will be included in the submission and appear in your FormWit dashboard and email notification.

Why not use a Framer form plugin?

Third-party Framer form plugins exist, but most have limitations:

  • Many require a separate monthly subscription on top of Framer's hosting fee
  • Some store submissions only within their own platform, with no email notifications
  • Plugin support can be inconsistent since they are maintained by independent developers
  • Switching plugins later means rebuilding your form from scratch

A form backend like FormWit gives you a stable, standards-based solution. Your form is plain HTML (or a React component in Framer's case), so it is easy to maintain, extend, and migrate if needed.

Summary

Framer does not include native form handling, but adding a contact form is straightforward with a form backend. Create a code component in Framer, point it at a FormWit endpoint, and publish. You get email notifications, spam protection, and a full submissions dashboard without any server-side code.

FormWit's free plan includes unlimited forms, 100 submissions per month, email notifications, and built-in spam protection. Create your free account and connect a contact form to your Framer site in minutes.

Related guides: Webflow contact form · HTML contact form · React contact form · Spam protection · Contact form templates

Want to skip the setup?

FormWit gives you a form endpoint in 60 seconds. Free plan, no credit card.

Create Free Form

Need a form fast?

Build one visually with our free HTML form generator — no coding required.

Try the Form Generator →

Connect your Framer form

Add a contact form to your site in 30 seconds. No backend code required.

Try FormWit Free