Skip to main content
New:Build with AI agents

Vite contact forms
without server glue.

Keep your Vite frontend fast and static-friendly. Form Plume gives your contact form a hosted endpoint for email, submissions, spam protection, files, integrations, and webhooks.

Free foreverNo credit cardVite endpoint ready in under a minute
.env + ContactForm.tsx
const endpoint = import.meta.env.VITE_FORM_PLUME_ENDPOINT;

async function onSubmit(event) {
  event.preventDefault();

  const response = await fetch(endpoint, {
    method: "POST",
    headers: { Accept: "application/json" },
    body: new FormData(event.currentTarget),
  });

  return response.ok;
}

The full guide

A Vite-friendly contact form backend.

Follow the Vite guide for environment-backed endpoints, React and vanilla examples, and the common local development caveats.

  1. 1
    Create your Form Plume accountStart free and give your Vite form a hosted endpoint for email, submissions, spam filtering, uploads, integrations, and webhooks.Start free
  2. 2
    Create the form and copy the endpointCopy the endpoint URL from Form Plume. It looks like https://api.formplume.com/f/your-slug
  3. 3
    Connect it inside ViteStore the public endpoint in a VITE_ environment variable or a local constant, then post FormData from the browser. Send one test submission from the real Vite app or preview environment and confirm it reaches Form Plume.

You can use this AI prompt to hand the platform-specific wiring to an assistant without accidentally creating a backend.

Configure the endpoint the Vite way

Vite exposes only variables that start with VITE_ to browser code. That is fine for a Form Plume endpoint because the endpoint is meant to receive public form submissions.

VITE_FORM_PLUME_ENDPOINT="PASTE_YOUR_FORM_PLUME_ENDPOINT_HERE"

Keep secrets out of Vite environment variables. Form Plume handles the protected work on its side: email notifications, spam filtering, stored submissions, uploads, integrations, and webhooks.

React in Vite

If your Vite app uses React, submit with FormData and a small status state.

import { useState, type FormEvent } from "react";
 
const endpoint = import.meta.env.VITE_FORM_PLUME_ENDPOINT;
 
export function ContactForm() {
  const [status, setStatus] = useState("idle");
 
  async function onSubmit(event: FormEvent<HTMLFormElement>) {
    event.preventDefault();
    setStatus("sending");
 
    const response = await fetch(endpoint, {
      method: "POST",
      headers: { Accept: "application/json" },
      body: new FormData(event.currentTarget),
    });
 
    setStatus(response.ok ? "sent" : "error");
  }
 
  return (
    <form onSubmit={onSubmit}>
      <label htmlFor="email">Email</label>
      <input id="email" type="email" name="email" required />
 
      <label htmlFor="message">Message</label>
      <textarea id="message" name="message" rows={5} required />
 
      <button disabled={status === "sending"}>
        {status === "sending" ? "Sending..." : "Send message"}
      </button>
 
      {status === "sent" && <p role="status">Thanks, we got your message.</p>}
      {status === "error" && <p role="alert">Please try again.</p>}
    </form>
  );
}

Vanilla Vite

For a Vite app without a framework, keep the endpoint in the script and let the HTML own the fields.

const endpoint = import.meta.env.VITE_FORM_PLUME_ENDPOINT;
const form = document.querySelector<HTMLFormElement>("#contact");
const status = document.querySelector<HTMLElement>("#status");
 
form?.addEventListener("submit", async (event) => {
  event.preventDefault();
  status!.textContent = "Sending...";
 
  const response = await fetch(endpoint, {
    method: "POST",
    headers: { Accept: "application/json" },
    body: new FormData(form),
  });
 
  status!.textContent = response.ok
    ? "Thanks, we got your message."
    : "Try again in a moment.";
});

Local development caveats

Restart the Vite dev server after changing .env values. Vite reads environment variables at startup.

Use a production endpoint for production builds and a test endpoint while building. The endpoint is public, but separating test and production submissions keeps your dashboard clean.

Vite does not give you a backend by itself. Avoid adding an Express server or serverless function just to send form email; let Form Plume handle that pipeline.

Best practices for Vite forms

Prefer FormData over JSON when the form may later include attachments.

Keep every field named. Form Plume can only store and route fields that arrive in the request.

Use visible labels and status text. Vite makes interactive forms easy, but accessibility still depends on the markup you ship.

When you add integrations, let Form Plume fan out accepted submissions rather than posting to multiple tools from the browser.

Primary sources

FAQ

Vite form questions
before deploy.

Use a VITE_FORM_PLUME_ENDPOINT environment variable or a local constant. VITE_ variables are public browser configuration, which is appropriate for a public Form Plume form endpoint.

One line. Zero backend.

The form backend you don’t have to build.

Free foreverNo credit cardSet up in under a minute