send.webforms.toRead the docs →

Frameworks and libraries

Add a contact form to a Vue app

Vue's reactivity makes the form itself easy; it is everything after submit that costs a weekend. WebForms handles the after: a POST from your component gets validated, spam-filtered, stored and routed wherever you like. The examples use the Composition API with `<script setup>`, and work identically in Vue 3 SPAs, Nuxt and Vue sprinkled into a static page.

Get an endpointRead the docs

Setup

  1. Create your endpoint

    Make a form in the dashboard and copy the endpoint URL it gives you.

  2. Post from your component

    Either pass the native FormData through, or bind fields with v-model and send JSON. Both examples are below.

  3. Route the submissions

    Add email, Slack, Discord, Telegram or webhook destinations in the dashboard. No redeploy needed when you change them.

Vue examples

Swap in your own endpoint and these run as-is.

FormData version - no per-field refs needed.

ContactForm.vue
<script setup>
import { ref } from "vue";

const status = ref("idle");
const error = ref(null);

async function onSubmit(e) {
  status.value = "sending";

  const res = await fetch("https://send.webforms.to/wft_your_key", {
    method: "POST",
    headers: { accept: "application/json" },
    body: new FormData(e.target),
  });

  const data = await res.json();

  if (data.ok) {
    status.value = "sent";
  } else {
    error.value = data.message;
    status.value = "error";
  }
}
</script>

<template>
  <p v-if="status === 'sent'" role="status">Thanks, we got it.</p>

  <form v-else @submit.prevent="onSubmit">
    <input name="name" required />
    <input name="email" type="email" required />
    <textarea name="message" required />

    <!-- honeypot -->
    <input name="_gotcha" tabindex="-1" aria-hidden="true"
           style="position:absolute;left:-9999px" />

    <button :disabled="status === 'sending'">
      {{ status === 'sending' ? 'Sending…' : 'Send' }}
    </button>
    <p v-if="error" role="alert">{{ error }}</p>
  </form>
</template>

v-model version, posting JSON.

ContactForm.vue
<script setup>
import { reactive, ref } from "vue";

const form = reactive({ name: "", email: "", message: "" });
const sending = ref(false);
const sent = ref(false);

async function onSubmit() {
  sending.value = true;

  const res = await fetch("https://send.webforms.to/wft_your_key", {
    method: "POST",
    headers: {
      "content-type": "application/json",
      accept: "application/json",
    },
    body: JSON.stringify(form),
  });

  sending.value = false;
  sent.value = res.ok;
}
</script>

<template>
  <p v-if="sent">Thanks, we got it.</p>
  <form v-else @submit.prevent="onSubmit">
    <input v-model="form.name" required />
    <input v-model="form.email" type="email" required />
    <textarea v-model="form.message" required />
    <button :disabled="sending">Send</button>
  </form>
</template>

Vue form FAQ

No. Vue posts straight to your endpoint from the browser. Nothing else to host.

Ready to wire up your Vue form?

Free for 300 submissions a month. Endpoint in under a minute, no card required.

Start free