Common Vue.js Gotchas


While this tutorial has content that we believe is of great benefit to our community, we have not yet tested or edited it to ensure you have an error-free learning experience. It's on our list, and we're working on it! You can help us out by using the "report an issue" button at the bottom of the tutorial.

As with any framework, Vue has a few oddities that might take newcomers a little while to get used to, and many stumble over. Here, we’ll attempt to list a number of those and how to work with and/or around them.

Installation & Building


While Vue is often cited as a *“progressive”* web framework, allowing you to only use the pieces you need little by little, if you wish to create a full application, you will definitely want a proper build system. Most commonly in the Vue community, Webpack is used.

Recognizing that Webpack is often hard for first-timers to understand, Vue offers vue-cli to help get a working scaffold ready for your app from the start. We use this in a number of our articles to establish a common base.

Versions (1.x vs 2.x)

Unlike with Angular 1 vs Angular 2, the two major releases of Vue, while changing many things under-the-hood, have very, very similar usage. So much so that if you don’t know what to look for, you won’t recognize if a component is written for Vue 1 or Vue 2. This can be problematic as compiled distributed files for Vue 1 won’t work with Vue 2, and vice-versa.

Here are a few signs of which version a component has been written for:

  • Does the component have a ready() (Vue 1) or a mounted() (Vue 2) method?
  • Does the component use v-bind.sync= attributes? Those are Vue 1 only.
  • Are filters being used outside of mustache expressions ({{}})? (ie. @click="thing() | debounce 200") That was removed in Vue 2.
  • Are partials being defined or used anywhere? (Vue 1)
  • Do you see any render() functions? The virtual DOM (and therefore, the render method) was added in Vue 2.
  • Are $broadcast and $dispatch being used anywhere? Those were removed in Vue 2 in lieu of a global event bus and provide / inject.
  • Is the order of arguments in v-for (index, item) or (key, val) (Vue 1) or the inverse (Vue 2)?

An advantage of these minor differences is that it’s incredibly straightforward to port a component from Vue 1 to Vue 2.


Vue’s reactivity system is great, but it doesn’t handle quite everything. There are a few edge cases that Vue can’t detect. (Yet. Hopefully when ES6 Proxies are widely supported these caveats will be gone.)

  1. When properties are added or removed from an object, Vue won’t know about it and won’t make them reactive.
  2. You can’t add new properties to the root data object directly, but you can use Vue.set(this.data, ‘propname’, value)
  3. Vue can’t detect when a particular index value changes in an array from setting it directly through array[index] = value. The workaround is to use Vue.set(array, index, value)
  4. Vue can’t detect when the length of an array changes. Use splice instead.


If using a module system, always make sure to Vue.use(plugins) before you try to use them. Otherwise you may be left scratching your head as to what went wrong. For some reason a lot of people seem to have trouble with this.


v-for without keys

Using v-for on arrays of objects without a key binding can result in some very strange rendering when the array changes. This is because Vue doesn’t know how to identify which objects changed without a key binding. The solution to this is to use :key=“obj.prop” to bind to a unique property on the object. (This is, in-fact, required in recent versions of Vue.)


  • Custom delimiters (via the delimiters) option are only available in the standalone build. (The one most often loaded via a script tag.) They don’t work in the npm versions.

HTML interpolation.

Many people don’t seem to know about the v-html binding which allows you to render html as an element’s children.

NOTE: You cannot use bindings and the likes inside of injected HTML. Use components for that instead.


The ref attribute on an element allows you to access the rendered element inside of your component. USE THIS IN PLACE OF IDS, IF YOU REALLY NEED THEM!

Hopefully this list helped you out! We plan to expand it in the future as needed.

Creative Commons License