Static site generators
Add a contact form to a Vite app
Vite builds a static bundle, so there is no server in the output to handle a form. That is fine: post straight to an endpoint from the client. Put the URL in an env var so dev and production can point at different forms, and keep the submit logic in one module you can import from any component.
Setup
Add the endpoint to .env
Vite only exposes variables prefixed with VITE_ to client code.
Write a submit helper
One module, importable from vanilla JS or any framework you are using with Vite.
Call it from your component
The helper returns the parsed JSON response.
Vite examples
Swap in your own endpoint and these run as-is.
VITE_FORM_ENDPOINT=https://send.webforms.to/wft_your_key
const ENDPOINT = import.meta.env.VITE_FORM_ENDPOINT;
export async function submitForm(form) {
const res = await fetch(ENDPOINT, {
method: "POST",
headers: { accept: "application/json" },
body: new FormData(form),
});
return res.json();
}Vanilla usage. Import the same helper from a React, Vue or Svelte component instead if you are using one.
import { submitForm } from "./submit.js";
const form = document.querySelector("#contact");
const result = document.querySelector("#result");
form.addEventListener("submit", async (e) => {
e.preventDefault();
const data = await submitForm(form);
result.textContent = data.ok ? "Thanks, we got it." : data.message;
if (data.ok) form.reset();
});Worth knowing
- VITE_ variables are inlined into the client bundle at build time and are therefore public. That is fine for a submit key, which identifies a form rather than authorising access. Never put a secret behind a VITE_ prefix.
Vite form FAQ
Yes. Those variables are baked into the public bundle, and the submit key is public by design. Restrict which domains may post to the form in the dashboard rather than trying to hide the key.
Related guides
Ready to wire up your Vite form?
Free for 300 submissions a month. Endpoint in under a minute, no card required.
Start free