Skip to content

Vue Forms

Vue 3’s composition API makes form handling clean. Here’s how to connect a form to Formkove.

<script setup>
import { ref } from "vue";
const name = ref("");
const email = ref("");
const message = ref("");
const status = ref("");
const error = ref("");
const submitForm = async () => {
status.value = "Sending...";
error.value = "";
try {
const res = await fetch("https://app.formkove.com/api/forms/YOUR_FORM_ID/submissions", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Accept": "application/json"
},
body: JSON.stringify({
name: name.value,
email: email.value,
message: message.value
})
});
const json = await res.json();
if (res.ok) {
status.value = "Message sent!";
name.value = "";
email.value = "";
message.value = "";
} else {
error.value = json.error || "Something went wrong.";
status.value = "";
}
} catch (err) {
error.value = "Network error. Check your connection.";
status.value = "";
}
};
</script>
<template>
<form @submit.prevent="submitForm">
<input
type="text"
v-model="name"
placeholder="Your name"
required
/>
<input
type="email"
v-model="email"
placeholder="Email address"
required
/>
<textarea
v-model="message"
placeholder="Your message"
required
></textarea>
<button type="submit">
{{ status.value || "Send" }}
</button>
<p v-if="error.value">{{ error.value }}</p>
</form>
</template>
<script setup>
import { ref, computed } from "vue";
const form = ref({
name: "",
email: "",
message: ""
});
const status = ref("");
const error = ref("");
const isValid = computed(() => {
return form.value.name && form.value.email && form.value.message;
});
const submitForm = async () => {
if (!isValid.value) return;
status.value = "Sending...";
error.value = "";
try {
const res = await fetch("https://app.formkove.com/api/forms/YOUR_FORM_ID/submissions", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Accept": "application/json"
},
body: JSON.stringify(form.value)
});
const json = await res.json();
if (res.ok) {
status.value = "Sent! We'll be in touch.";
form.value = { name: "", email: "", message: "" };
} else {
error.value = json.error || "Something went wrong.";
status.value = "";
}
} catch (err) {
error.value = "Network error. Check your connection.";
status.value = "";
}
};
</script>
<template>
<form @submit.prevent="submitForm">
<input
type="text"
v-model="form.name"
placeholder="Full name"
required
/>
<input
type="email"
v-model="form.email"
placeholder="Email address"
required
/>
<textarea
v-model="form.message"
placeholder="What's on your mind?"
required
></textarea>
<button type="submit" :disabled="!isValid || status === 'Sending...'">
{{ status || "Send Message" }}
</button>
<p v-if="error" class="error">{{ error }}</p>
</form>
</template>
  • Form ID in the URL path (not a hidden field)
  • Use Content-Type: application/json with fetch
  • Clear the form (form.value = {...}) after success
  • Use v-model to bind form fields reactively