The Complete Vue.js Event System Guide That The Official Doc Didn’t Explain In Detail — Part 1

Chris Y.
6 min readApr 6, 2022


Event Handling

Vue.js is implemented with a powerful yet easy-to-use event system that covers most of our daily development needs when it comes to user interaction. In this series, we will go through all parts of the event system in Vue that you could possibly use in your projects.

Let’s start off with Event Handling.


Here’s a simple Vue component with a line of text and a button:

When the user clicks on the button, we want to show a dialog with a message. So we need to bind a click event onto the <button> element. To bind an event onto an element in Vue's template, we can use Vue's v-on directive, and the event is the built-in click event:

Normally we will use v-on's shortcut @:

This means when the <button> element is clicked, Vue will try to find a callback function (event handler) named showDialog and execute it. We now need to define this function.

If we define a normal JavaScript function like the below:

Will it work when clicking the button?

It won’t work, and we got the error in the console:

“Property or method “showDialog” is not defined on the instance…”

This indicates the callback function must be defined on the instance, in our case here, on a VueComponent instance (because we are within a Vue component). The place to put a function on a VueComponent instance is the methods option, so let's move the callback into it:

The alert dialog is now shown.

Use v-on:xxxx or @xxxx to bind (listen to) an event. xxxx is the event name that can be a built-in event such as click, or a custom event.

Passing arguments

Can the showDialog method get arguments? Yes, actually if we add a parameter in the function definition and print it out after clicking:

We can see it is the event object (of type PointerEvent, which is the native DOM event). Because it is the native event, we can access its target property:

By default, Vue will pass the native DOM object as the first argument into the event callback function (event handler).

Now if we want to pass an argument to showDialog from the template, we can put the argument in the parenthesis after the method name. For example:

It works as expected, but we might still want to access the event object, so can we do this?

No, the output is undefined. To solve this issue, Vue implemented a keyword $event, and if we add it as the second argument in the template:

The method receives the event object.

$event works like a placeholder in Vue's template. When Vue parses the template and scans the $event, it will replace it with the DOM event object.

Can we switch the order of text and $event, like this?

Yes, then $event will be passed to the 1st parameter defined in the method, and text to the 2nd parameter.

The order of arguments in the template is the order they are passed to the parameters of the event callback.

@click="showDialog()"works the same as @click="showDialog($event)", the difference is the second form allows you to access the event object and pass arguments.

`this` inside event callbacks

Now let’s look at the this inside our event callback method by printing it out:

It points to the current component, that is, a VueComponent instance. On this instance, we can see the event callback showDialog defined in the methods option. The [[TargetFunction]] is ƒ showDialog(event, text), which means Vue will execute this ƒ showDialog(event, text) function when the event is triggered. Also [[BoundThis]] indicates the this keyword in showDialog is bound to the current VueComponent instance (current component). This is automatically done by Vue, and we can verify it:

We created a data property and save the value of this in mounted, which points to the current component instance. Then in the showDialog method body, we do a comparison, and both this and this.instance point to the same object:

So far, we have defined showDialog as a traditional function, what if changing it to an arrow function?

Now the this inside showDialog becomes undefined, and this is because arrow functions don't have their own this binding. Therefore, when line 15 refers to this, it will go up and look in the outer context, which is none, so this in line 15 gets undefined.

All functions that are managed by Vue, e.g. methods, computed functions, watchers, etc. are better to be traditional functions. This can ensure their this always points to the current VueComponent instance. (The binding is done by Vue when it creates the component instance.)

All right, this concludes Part 1 of this series, see you in the next section.

Here are some more articles on Vue.js:

Vue.js Components Communication Patterns (without Vuex) — Part 1

Vue.js Components Communication Patterns (without Vuex) — Part 2

Vue.js Components Communication Patterns (without Vuex) — Part 3

Vue.js Components Communication Patterns (without Vuex) — Part 4

Vue.js Components Communication Patterns (without Vuex) — Part 5

Vue.js Components Communication Patterns (without Vuex) — Part 6

Vue.js Components Communication Patterns (without Vuex) — Part 7

Build your own Vue.js UI library based on Vuetify and publish it to NPM