Skip to content
Framework guide

Add a contact form to a Vue app

A Vue single-file component can post a contact form to Formwire with fetch and switch to a thank-you state on the reply. This guide gives you the component in script setup form, ready for Vite or Nuxt.

4 min read

The form

Replace YOUR-ACCESS-KEY with the key from your form's page. The highlighted line is the one that points the form at Formwire.

src/components/ContactForm.vue

            1
            <!-- src/components/ContactForm.vue -->
          
            2
            <script setup>
          
            3
            import { ref } from "vue";
          
            4
             
          
            5
            const status = ref("idle");
          
            6
             
          
            7
            async function onSubmit(e) {
          
            8
              status.value = "sending";
          
            9
              const body = new FormData(e.target);
          
            10
              body.append("access_key", "YOUR-ACCESS-KEY");
          
            11
              const res = await fetch("https://formwire.io/submit", {
          
            12
                method: "POST",
          
            13
                headers: { Accept: "application/json" },
          
            14
                body,
          
            15
              });
          
            16
              const { success } = await res.json();
          
            17
              status.value = success ? "sent" : "error";
          
            18
            }
          
            19
            </script>
          
            20
             
          
            21
            <template>
          
            22
              <p v-if="status === 'sent'">Thanks, your message is on its way.</p>
          
            23
              <form v-else @submit.prevent="onSubmit">
          
            24
                <input type="text" name="fax" tabindex="-1" autocomplete="off" style="display:none" />
          
            25
                <label for="name">Name</label>
          
            26
                <input id="name" name="name" type="text" required />
          
            27
                <label for="email">Email</label>
          
            28
                <input id="email" name="email" type="email" required />
          
            29
                <label for="message">Message</label>
          
            30
                <textarea id="message" name="message" rows="5" required></textarea>
          
            31
                <button type="submit" :disabled="status === 'sending'">
          
            32
                  {{ status === "sending" ? "Sending" : "Send" }}
          
            33
                </button>
          
            34
                <p v-if="status === 'error'">Something went wrong. Please try again.</p>
          
            35
              </form>
          
            36
            </template>
          

Steps

  1. 1

    Create a form and copy its access key

    Sign up at app.formwire.com and create a form. Your sign-in address receives its submissions from the start. The access key is on the form's Settings tab, under General.

  2. 2

    Add the component

    Create src/components/ContactForm.vue with the code above and replace YOUR-ACCESS-KEY with your key. @submit.prevent stops the browser navigating so the component can show its own state.

  3. 3

    Use it in a page

    Import and render the component. In Nuxt, drop it in components/ and it is auto-imported.

    vue
    
                1
                <script setup>
              
                2
                import ContactForm from "./components/ContactForm.vue";
              
                3
                </script>
              
                4
                 
              
                5
                <template>
              
                6
                  <main>
              
                7
                    <h1>Contact</h1>
              
                8
                    <ContactForm />
              
                9
                  </main>
              
                10
                </template>
              
  4. 4

    Send a test submission

    Open the app in your browser, fill the form in and send it. The submission appears in the form's inbox in the dashboard within a few seconds and the notification email follows, with Reply-To set to the address the visitor typed.

Notes for Vue

  • Nuxt: the component runs the fetch in the browser, so it works the same with ssr: true or a static generate. No server route is needed.
  • To bind fields with v-model instead of FormData, build a plain object and send it as JSON with Content-Type application/json, with access_key included.
  • The Accept: application/json header makes Formwire answer with JSON, so the hidden redirect field is not used here. Add it and remove @submit.prevent if you want a full-page redirect instead.

Questions

Does this work with Nuxt and server-side rendering?

Yes. The form is rendered on the server like any component, and the fetch runs in the browser on submit. Nothing in server/ is needed.

Is the access key safe to put in client-side code?

Yes. The access key is a public ID that can only deliver submissions to the inbox you verified. It cannot read submissions or change settings, and you can rotate it from the form's settings if it is ever abused.

How does the form stop spam without a captcha?

The hidden fax field is a honeypot: a submission that fills it in goes to the Spam folder and nobody is emailed. A spam filter and rate limits also run on every form. Settings, Spam & security has the filter level, and on Pro, allowed domains.

Where do submissions go?

Each submission is stored in the form's inbox in the dashboard and emailed to you with Reply-To set to the visitor. On Pro it can also go to more recipients and to webhooks. The inbox exports to CSV and JSON.

All guides