JavaScript framework
Vue form handling without a backend
Vue is a frontend framework, so a contact or signup form has no built-in place to send data. Rather than wiring up a Node server or a serverless function, you can submit straight to Formward — an EU-hosted form backend — and keep your Vue app entirely client-side.
The single-file component below uses the Composition API. A submit handler builds FormData from the form element, posts it with fetch(), and flips a reactive status ref so the template can show a spinner, a success message, or an error.
EU-hosted · Vue on the edge, data in Sweden: submissions are processed entirely within the EU, so a GDPR record of processing stays short and honest.
The Vue example
Copy this into your project and replace <FORM_ID> with the id of a form you create in the Formward dashboard.
vue
<script setup>
import { ref } from "vue";
const status = ref("idle"); // idle | sending | ok | error
async function onSubmit(e) {
status.value = "sending";
const form = e.target;
try {
const res = await fetch("https://forms.formward.eu/f/<FORM_ID>", {
method: "POST",
headers: { Accept: "application/json" },
body: new FormData(form),
});
const data = await res.json(); // { ok: true, id, files }
if (!res.ok || !data.ok) throw new Error(data.error || res.status);
form.reset();
status.value = "ok";
} catch {
status.value = "error";
}
}
</script>
<template>
<p v-if="status === 'ok'">Thanks — we received your message.</p>
<form v-else @submit.prevent="onSubmit">
<input type="email" name="email" required />
<textarea name="message" required></textarea>
<input type="text" name="_gotcha" tabindex="-1" autocomplete="off"
style="display:none" aria-hidden="true" />
<button :disabled="status === 'sending'">
{{ status === "sending" ? "Sending…" : "Send" }}
</button>
<p v-if="status === 'error'" role="alert">Could not send. Try again.</p>
</form>
</template>Success and error handling
- @submit.prevent stops the native navigation so your fetch() handles the request and the user stays on the page.
- Asking for Accept: application/json makes Formward reply with { ok: true, id, files }; without it the endpoint sends a 302 redirect suited to no-JS forms.
- The hidden _gotcha honeypot must stay empty — Formward drops filled-in submissions as spam before they reach your inbox.
Spam protection
Every example above includes the _gotcha honeypot field. It is hidden from real users and must stay empty; Formward silently drops any submission where it is filled, which stops most bots with no CAPTCHA. For a stricter gate, add a Cloudflare Turnstile widget and send its token as the cf-turnstile-response field — Formward verifies it on receipt.
The JSON response
A standard POST gets a 302 redirect (or your thank-you page). Send the Accept: application/json header — as every fetch() example above does — and Formward returns JSON instead:
HTTP/1.1 200 OK
Content-Type: application/json
{ "ok": true, "id": "clxyz123...", "files": [] }On failure the body is { ok: false, error } with a 4xx status (validation, plan limit, and so on). See the AJAX docs for the full status-code table and CORS notes.
Other frameworks
Collect your first Vue submission
Create a form, paste the snippet, and keep every submission in the EU. GDPR-clean from the first POST.