Skip to the solution
EasyFrontend9 min read

How do you handle events in Vue (v-on and event modifiers)?

1.1k views

The problem

Question presented to candidate: "A form needs a submit button that must not reload the page, a search box that reacts to Enter, and a card whose inner buttons must not trigger the card click. How do you handle these events in Vue?"

What a strong answer should cover:

  • v-on:event or the shorthand @event attaches a listener; the value is a method handler (@click="save", receives the native event) or an inline handler (@click="save(item.id)", use $event to get the event).
  • Event modifiers replace boilerplate: .prevent (preventDefault), .stop (stopPropagation), .self, .once, .capture, .passive.
  • Key modifiers (@keyup.enter, .esc, .tab, .delete, arrow keys, or any kebab-case KeyboardEvent.key), system modifiers (.ctrl, .alt, .shift, .meta), .exact and mouse buttons (.left, .right, .middle).
  • Modifiers can be chained and order matters (.prevent.self differs from .self.prevent).
  • On components, @event listens to events the child emits (declared with defineEmits); Vue 2 .native no longer exists.
  • Template listeners are attached directly to each element (no global delegation) and go away with the element when it is removed; listeners you add yourself to window or document must be removed in onUnmounted.

Clarifying questions expected:

  • "Is this a native DOM element or a custom component emitting events?"

Code / implementation expected: Yes. A template showing @submit.prevent, @keyup.enter and @click.stop.

  • vue
  • events
  • v-on
  • modifiers

Try it yourself

Sketch your approach before you read the solution. That is what the interview tests.

Stuck? Get a hint.

A short nudge toward the approach. It will not give the answer away.

Solution

The solution is hidden so you can try first

9 min read Β· 10 sections

Read the code

VueMethod and inline handlers, $event, and the common event, key and system modifiers
<script setup>
import { ref } from "vue";

const log = ref([]);
const note = (msg) => log.value.push(msg);

// Method handler: Vue passes the native event as the first argument.
function onSave(event) {
  note(`save (${event.type} on ${event.target.tagName})`);
}
</script>

<template>
  <!-- method handler vs inline handler with $event -->
  <button class="save" @click="onSave">Save</button>
  <button class="inline" @click="note('inline ' + $event.type)">Inline</button>

  <!-- .stop: the click does not bubble up to the outer div -->
  <div class="outer" @click="note('outer div')">
    <button class="plain">bubbles</button>
    <button class="stop" @click.stop="note('stopped')">stop</button>
  </div>

  <!-- .self: only when the click starts on this element, not a child -->
  <div class="self" @click.self="note('self div')"><span class="child">child</span></div>

  <!-- .prevent: no page reload on submit -->
  <form class="form" @submit.prevent="note('submitted without reload')"><button>Send</button></form>

  <!-- .once: the handler is removed after the first call -->
  <button class="once" @click.once="note('once')">Once</button>

  <!-- key modifiers -->
  <input class="search" @keyup.enter="note('enter pressed')" @keyup.esc="note('esc pressed')" />

  <!-- .exact: Ctrl+click only, with no other system key -->
  <button class="exact" @click.ctrl.exact="note('ctrl only')">Ctrl-click</button>

  <ol class="log"><li v-for="(m, i) in log" :key="i">{{ m }}</li></ol>
</template>
VueModifier order matters: .prevent.self vs .self.prevent
<script setup>
import { ref } from "vue";
const log = ref([]);
</script>

<template>
  <a class="a" href="#one" @click.prevent.self="log.push('a')"><span class="sa">child A</span></a>
  <a class="b" href="#two" @click.self.prevent="log.push('b')"><span class="sb">child B</span></a>
  <p class="out">{{ log.join(",") }}</p>
</template>

Discussion

Other approaches, follow-ups and how it went in real interviews.

Sign in to join the discussion.

No comments yet. Share how you would answer it.

Question 1 of 92 in Vue.js

Keep your momentum going.

Mark this question solved to track your progress, then take the next one while it is fresh.

All Vue.js questions
Up nextEasy

What is Vue.js and what are its core features?

Continue