Contact form for Vue and Nuxt

A Vue contact form is a template, a reactive status ref, and one fetch call. The same component works in Vite-powered Vue SPAs and in Nuxt (including nuxt generate static sites) because nothing here needs a server.

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

const status = ref("idle");

async function onSubmit(e) {
  status.value = "sending";
  const data = Object.fromEntries(new FormData(e.target));
  const res = await fetch("https://formdock.app/f/your-form-key", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify(data),
  });
  status.value = res.ok ? "sent" : "error";
}
</script>

<template>
  <p v-if="status === 'sent'">Thanks — we got your message.</p>
  <form v-else @submit.prevent="onSubmit">
    <input name="name" required placeholder="Name" />
    <input name="email" type="email" required placeholder="Email" />
    <textarea name="message" placeholder="Message"></textarea>
    <button :disabled="status === 'sending'">Send</button>
    <p v-if="status === 'error'">Something went wrong — try again.</p>
  </form>
</template>
  • In Nuxt, put the endpoint in runtimeConfig.public and read it with useRuntimeConfig() instead of hardcoding.
  • FormData picks up every named input automatically — add fields to the template and they arrive in your dashboard without code changes.
  • The submitter's email field becomes the Reply-To on your notification email.

Get your endpoint: create a free FormDock account (100 submissions/month), add a form, and swap your-form-key for the real key.