// Tutorial //

PSA: Proper Form Handling in Vue.js

Published on November 6, 2017
Default avatar
By Joshua Bemenderfer
Developer and author at DigitalOcean.
PSA: Proper Form Handling in Vue.js

Forms are an integral part of almost any web application. They’re really just ways of getting information from the user and turning it into some sort of machine-readable data model. Thing is, not everyone realizes exactly how the HTML form element works, and how it can simplify their lives, especially when it comes to handling user submission and event binding in libraries like Vue.js. Now’s the time to set the record straight.

The Bad Way

More often then not, I see people doing things like this: (Binding their data submission handlers to the parent element and button click event.)

<template>
  <div @keydown.enter="handleSubmit">
    <label>
      Email:
      <input type="email" v-model="user.email"/>
    </label>
    <label>
      Name:
      <input type="text" v-model="user.name"/>
    </label>
    <label>
      Password:
      <input type="password" v-model="user.password"/>
    </label>
    <button @click="handleSubmit">Submit</button>
  </div>
</template>

<script>
export default {
  data() {
    return {
      user: {
        email: '',
        name: '',
        password: ''
      }
    }
  },

  methods: {
    handleSubmit() {
      // Send data to the server or update your stores and such.
    }
  }
}
</script>

Now, there are dozens of reasons that this is a bad idea. For one thing, it makes it difficult for screen readers and the likes to know that they’re in a form. Additionally, you have to bind the event handler to both the button and the containing element, and it still doesn’t really handle every use-case. You should pretty much never be doing anything like this.

The Good Way

So what should you be doing? Well, actually it’s really simple. Use the <form> element!

<template>
  <!-- @submit handles any form of submission. -->
  <!-- .prevent keeps the event from bubbling around and doing anything else. -->
  <form @submit.prevent="handleSubmit">
    <label>
      Email:
      <input type="email" v-model="user.email"/>
    </label>
    <label>
      Name:
      <input type="text" v-model="user.name"/>
    </label>
    <label>
      Password:
      <input type="password" v-model="user.password"/>
    </label>
    <button type="submit">Submit</button>
  </form>
</template>

<script>
export default {
  data() {
    return {
      user: {
        email: '',
        name: '',
        password: ''
      }
    }
  },

  methods: {
    handleSubmit() {
      // Send data to the server or update your stores and such.
    }
  }
}
</script>

Boom. Clicking the button is handled. Pressing enter is handled. Any other method of form submission, past, present, or future, is handled.

It seems quite a few front-end developers forget about or ignore the good 'ol <form> element. Possibly because of misconceptions / horrible memories from their traditional hosted PHP-rendered-page days. Often, the misconceptions that prevent developers from using the <form> element include these:

  • Assuming it forces a page refresh.
  • Assuming you have to set the method and action properties that make an uncontrollable request.
  • Assuming you have to set a unique name for your form.

None of those are true. With nothing else set, a form is really just a convenient wrapper for input fields that allows you to handle any form of submission the user chooses without any extra logic.

So go on and use <form>. I don’t want to see anyone else handling keypresses and button clicks manually for user input. Just use the element HTML gave you!


Want to learn more? Join the DigitalOcean Community!

Join our DigitalOcean community of over a million developers for free! Get help and share knowledge in our Questions & Answers section, find tutorials and tools that will help you grow as a developer and scale your project or business, and subscribe to topics of interest.

Sign up
About the authors
Default avatar
Developer and author at DigitalOcean.

Still looking for an answer?

Was this helpful?

I’ve been using this approach for a while now and feel like it’s the most programmatic approach and makes the most sense. I’m wondering though if instead of using the v-model, you can just pass along the values from the submit event to an Axios post request.