Skip to main content
Build a basic contact form in Vue that submits directly to PipedForm using fetch, with reactive state for handling submission status.

Basic Example

<script setup>
import { ref, reactive } from 'vue';

const state = reactive({
  status: 'idle',
  message: '',
});

const name = ref();
const email = ref();
const message = ref();

const onSubmit = async () => {
  state.status = 'loading';

  const res = await fetch('https://pipedform.com/f/{form_id}', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      name: name.value,
      email: email.value,
      message: message.value,
    }),
  });

  const data = await res.json();

  if (res.ok) {
    state.status = 'success';
    state.message = 'Form submitted successfully';
  } else {
    state.status = 'error';
    state.message = data.message;
  }
};
</script>

<template>
  <form @submit.prevent="onSubmit">
    <input name="name" v-model="name" placeholder="John" required />
    <input
      type="email"
      name="email"
      v-model="email"
      placeholder="[email protected]"
      required
    />
    <textarea
      name="message"
      v-model="message"
      placeholder="Enter your message..."
      required
    ></textarea>

    <p v-if="state.status === 'error'" style="color: red">
      {{ state.message }}
    </p>
    <p v-if="state.status === 'success'" style="color: green">
      {{ state.message }}
    </p>

    <button type="submit">
      <template v-if="state.status === 'loading'">Loading...</template>
      <template v-else>Send</template>
    </button>
  </form>
</template>