Vue contact forms
without backend work.
Keep your Vue component focused on fields and state. Form Plume handles email notifications, stored submissions, spam filtering, uploads, integrations, and signed webhooks.
const status = ref("idle");
async function submit(event: Event) {
const form = event.currentTarget as HTMLFormElement;
status.value = "sending";
const response = await fetch(FORM_PLUME_ENDPOINT, {
method: "POST",
body: new FormData(form),
});
status.value = response.ok ? "sent" : "error";
}The full guide
A clean backend path for Vue contact forms.
Use the Composition API, FormData, and accessible status messages without building your own delivery pipeline.
- 1Create your Form Plume accountStart free and give your Vue form a hosted endpoint for email, submissions, spam filtering, uploads, integrations, and webhooks.Start free
- 2Create the form and copy the endpointCopy the endpoint URL from Form Plume. It looks like
https://api.formplume.com/f/your-slug - 3Connect it inside VueUse a Vue 3 submit handler, send FormData from the form element, and render clear status text. Send one test submission from the real Vue 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.
Vue 3 Composition API form
Use @submit.prevent when you want inline status and no page navigation.
<script setup lang="ts">
import { ref } from "vue";
const FORM_PLUME_ENDPOINT = "PASTE_YOUR_FORM_PLUME_ENDPOINT_HERE";
const status = ref<"idle" | "sending" | "sent" | "error">("idle");
async function submit(event: Event) {
const form = event.currentTarget as HTMLFormElement;
status.value = "sending";
const response = await fetch(FORM_PLUME_ENDPOINT, {
method: "POST",
headers: { Accept: "application/json" },
body: new FormData(form),
});
if (response.ok) {
form.reset();
status.value = "sent";
} else {
status.value = "error";
}
}
</script>
<template>
<form @submit.prevent="submit">
<label for="name">Name</label>
<input id="name" name="name" autocomplete="name" required>
<label for="email">Email</label>
<input id="email" type="email" name="email" autocomplete="email" required>
<label for="message">Message</label>
<textarea id="message" name="message" rows="5" required />
<button :disabled="status === 'sending'">
{{ status === "sending" ? "Sending..." : "Send message" }}
</button>
<p v-if="status === 'sent'" role="status">Thanks, we got your message.</p>
<p v-if="status === 'error'" role="alert">Please try again.</p>
</form>
</template>Form Plume handles the backend parts that Vue should not own: email notifications, submissions dashboard, spam filtering, file uploads, integrations, and webhooks.
Keep the endpoint public but intentional
If you use Vite with Vue, a client-exposed endpoint can live in VITE_FORM_PLUME_ENDPOINT.
const FORM_PLUME_ENDPOINT = import.meta.env.VITE_FORM_PLUME_ENDPOINT;That endpoint is public by design. Do not put email provider keys or webhook secrets in the client bundle.
File uploads in Vue
Because the submit handler reads the real form element, uploads work without separate reactive state.
<form @submit.prevent="submit" enctype="multipart/form-data">
<label for="attachment">Attachment</label>
<input id="attachment" type="file" name="attachment" accept=".pdf,.png,.jpg">
<button>Send message</button>
</form>Do not manually set Content-Type when sending FormData.
Vue validation approach
Native required and type="email" validation are enough for many contact forms.
Use VeeValidate or another form library when the form has multi-step logic, conditional fields, or shared validation schemas.
Keep field names stable. Form Plume uses names like name, email, and message to make notifications, exports, and integrations easier to read.
If your Vue site is mostly static, a plain form action is also fine. Add JavaScript only when inline status improves the experience.
Triggering your workflow
After a Vue form is accepted, Form Plume can notify the team by email, store the full submission, send a Slack or Discord message, append to Google Sheets, add a Mailchimp or ActiveCampaign contact, or call your signed webhook.
Primary sources
FAQ
Vue form questions
before deploy.
One line. Zero backend.
