Basestack Docs

Vue

Vue.js is a progressive JavaScript framework for building user interfaces, designed to be approachable, versatile, and easy to integrate, with a focus on declarative rendering and component-based architecture.

Prerequisites

Before you begin, make sure you have:

Quick Setup Guide

Follow these steps to integrate Basestack Forms with your Vue.js application:

Choose your HTTP client

You can use any HTTP client library to send form data from your Vue component. Popular options include:

  • Fetch API - Built into modern browsers, no installation needed
  • Axios - Popular HTTP client with Vue-friendly features
  • Any other HTTP client that supports POST requests

Include mode=rest in your endpoint URL query string to receive JSON responses. This allows you to handle the response and show success or error messages to users.

Implement form submission handler

Copy the example component below into your Vue project. The example demonstrates:

  • Form state management using Vue's Composition API
  • Form submission with Fetch API
  • Basic error handling and success feedback

The example uses Vue 3's Composition API with reactive and toRefs. Adapt it to your Vue version and preferred API style.

form.vue
<template>
  <form @submit.prevent="onHandleSubmit">
    <div>
      <label for="name">Name</label>
      <input
        type="text"
        v-model="form.name"
        id="name"
        placeholder="Enter your name"
        name="name"
        required
        autocomplete="name"
        aria-label="Name"
      />
    </div>

    <div>
      <label for="email">Email</label>
      <input
        type="email"
        v-model="form.email"
        id="email"
        name="email"
        required
        autocomplete="email"
        aria-label="Email"
        placeholder="Enter your email"
      />
    </div>

    <div>
      <label for="message">Message</label>
      <textarea
        v-model="form.message"
        id="message"
        name="message"
        required
        aria-label="Message"
        placeholder="Enter your message"
      ></textarea>
    </div>

    <button type="submit">Submit</button>
  </form>
</template>

<script>
import { reactive, toRefs } from "vue";

export default {
  setup() {
    const form = reactive({
      name: "",
      email: "",
      message: "",
    });

    const onHandleSubmit = async () => {
      try {
        const res = await fetch(
          "https://forms-api.basestack.co/v1/s/[KEY]?mode=rest",
          {
            method: "POST",
            headers: {
              Accept: "application/json",
              "Content-Type": "application/json",
            },
            body: JSON.stringify(form),
          },
        );

        const data = await res.json();

        if (data.code === 200) {
          console.log("Form submitted successfully");
        }
      } catch (error) {
        console.log("Error submitting form", error);
      }
    };

    return {
      ...toRefs(form),
      onHandleSubmit,
    };
  },
};
</script>

Attaching files

File uploads must be enabled in Settings โ†’ General first (off by default on new forms). Use a FormData instance to send files alongside text fields. Don't set a Content-Type header manually, the browser fills it in (with the multipart boundary) for you.

Each file must be 1 MB or smaller, and a single submission may include at most 5 files. The server returns HTTP 413 if either limit is exceeded. See File Uploads โ†’ for full details.

Simple example: single file

contact-with-file.vue
<template>
  <form @submit.prevent="onHandleSubmit">
    <input v-model="form.name" name="name" placeholder="Name" required />
    <input
      v-model="form.email"
      type="email"
      name="email"
      placeholder="Email"
      required
    />
    <textarea
      v-model="form.message"
      name="message"
      placeholder="Message"
      required
    ></textarea>

    <input
      type="file"
      name="resume"
      accept="application/pdf"
      @change="onPickFile"
    />

    <button type="submit">Send</button>
  </form>
</template>

<script>
import { reactive, ref, toRefs } from "vue";

export default {
  setup() {
    const form = reactive({ name: "", email: "", message: "" });
    const resume = ref(null);

    const onPickFile = (event) => {
      resume.value = event.target.files?.[0] ?? null;
    };

    const onHandleSubmit = async () => {
      const formData = new FormData();
      formData.append("name", form.name);
      formData.append("email", form.email);
      formData.append("message", form.message);
      if (resume.value) formData.append("resume", resume.value);

      const res = await fetch(
        "https://forms-api.basestack.co/v1/s/[KEY]?mode=rest",
        {
          method: "POST",
          headers: { Accept: "application/json" },
          body: formData,
        },
      );
      const data = await res.json();
      if (data.code === 200) console.log("Submitted");
    };

    return { ...toRefs(form), resume, onPickFile, onHandleSubmit };
  },
};
</script>

Complex example: multiple files with validation

The pattern below holds picked files in a ref, validates size and count before submission, and lets the user remove individual files from the list.

application-with-files.vue
<template>
  <form @submit.prevent="onHandleSubmit">
    <input v-model="form.full_name" name="full_name" placeholder="Full name" required />
    <input v-model="form.email" type="email" name="email" placeholder="Email" required />

    <button type="button" :disabled="files.length >= MAX_FILES" @click="$refs.picker.click()">
      Attach files ({{ files.length }} / {{ MAX_FILES }})
    </button>
    <input
      ref="picker"
      type="file"
      multiple
      hidden
      @change="onPickFiles"
    />

    <ul>
      <li v-for="(file, index) in files" :key="`${file.name}-${index}`">
        {{ file.name }} ยท {{ (file.size / 1024).toFixed(1) }} KB
        <button type="button" @click="removeFile(index)">Remove</button>
      </li>
    </ul>

    <button type="submit">Submit application</button>
  </form>
</template>

<script>
import { reactive, ref, toRefs } from "vue";

const MAX_FILE_SIZE = 1 * 1024 * 1024;
const MAX_FILES = 5;

export default {
  setup() {
    const form = reactive({ full_name: "", email: "" });
    const files = ref([]);

    const onPickFiles = (event) => {
      const picked = Array.from(event.target.files ?? []);
      event.target.value = "";

      const remaining = Math.max(0, MAX_FILES - files.value.length);
      const accepted = [];

      for (const file of picked) {
        if (file.size > MAX_FILE_SIZE) {
          alert(`"${file.name}" exceeds the 1 MB limit.`);
          continue;
        }
        if (accepted.length >= remaining) {
          alert(`Up to ${MAX_FILES} files allowed.`);
          break;
        }
        accepted.push(file);
      }

      files.value = [...files.value, ...accepted];
    };

    const removeFile = (index) => {
      files.value = files.value.filter((_, i) => i !== index);
    };

    const onHandleSubmit = async () => {
      const formData = new FormData();
      formData.append("full_name", form.full_name);
      formData.append("email", form.email);
      for (const file of files.value) {
        formData.append("portfolio", file);
      }

      const res = await fetch(
        "https://forms-api.basestack.co/v1/s/[KEY]?mode=rest",
        {
          method: "POST",
          headers: { Accept: "application/json" },
          body: formData,
        },
      );
      const data = await res.json();
      if (data.code === 200) {
        files.value = [];
      } else {
        alert(data.message ?? "Submission failed.");
      }
    };

    return {
      ...toRefs(form),
      files,
      MAX_FILES,
      onPickFiles,
      removeFile,
      onHandleSubmit,
    };
  },
};
</script>

On this page