Handling Events

beginner
10 min

Handling Events

Interactive apps respond to what users do: clicks, key presses, form submissions, mouse movement. In Vue you listen to DOM events with the v-on directive -- almost always written with its shorthand @. This lesson covers inline handlers, method handlers, the event object, and Vue's powerful modifier system.

Listening with @

vue
<script setup> import { ref } from 'vue' const count = ref(0) function greet() { alert('Hello from Vue!') } </script> <template> <button @click="count++">Clicked {{ count }} times</button> <button @click="greet">Say hi</button> </template>

Two styles are shown here:

  • Inline handlers (count++) run a small expression right in the template -- fine for one-liners.
  • Method handlers (greet) reference a function, which is better for any real logic.

Accessing the Event Object

When you pass a bare method name, Vue calls it with the native Event as the first argument. When you need both custom arguments and the event, use the special $event variable or an arrow function:

vue
<template> <input @input="onInput"> <button @click="remove(item.id, $event)">Delete</button> <button @click="(e) => remove(item.id, e)">Delete (arrow)</button> </template> <script setup> function onInput(event) { console.log(event.target.value) } function remove(id, event) { console.log('removing', id, 'via', event.type) } </script>

Event Modifiers

Calling event.preventDefault() or event.stopPropagation() inside every handler is noisy. Vue lets you declare these concerns in the template with dot modifiers:

vue
<form @submit.prevent="onSubmit">…</form> <!-- no page reload --> <a @click.stop="select">…</a> <!-- stop bubbling --> <div @click.self="close">…</div> <!-- only if target is the div itself --> <button @click.once="init">…</button> <!-- fires a single time --> <div @scroll.passive="onScroll">…</div> <!-- hints better scroll performance -->

Modifiers can be chained: @click.stop.prevent="doThing". Order matters -- modifiers run left to right.

The @submit.prevent pattern is one of the most common in all of Vue: it keeps the browser from reloading the page so your JavaScript can handle the form instead.

Key Modifiers

For keyboard events you can filter by key without writing if statements:

vue
<input @keyup.enter="submit"> <input @keyup.escape="cancel"> <input @keydown.ctrl.s.prevent="save"> <!-- Ctrl+S without the browser dialog -->

Vue provides aliases for common keys: enter, tab, delete, esc, space, up, down, left, right. System modifier keys -- .ctrl, .alt, .shift, .meta -- combine with mouse and keyboard events. Add .exact when you want only those modifiers pressed: @click.ctrl.exact ignores Ctrl+Shift+Click.

Mouse buttons get modifiers too: .left, .right, .middle.

A Practical Example: Search Form

vue
<script setup> import { ref } from 'vue' const query = ref('') const results = ref([]) function search() { if (!query.value) return results.value = ['Result A for ' + query.value, 'Result B for ' + query.value] } function clear() { query.value = '' results.value = [] } </script> <template> <form @submit.prevent="search"> <input v-model.trim="query" @keyup.escape="clear" placeholder="Search…"> <button type="submit">Go</button> </form> <ul> <li v-for="r in results" :key="r">{{ r }}</li> </ul> </template>

Submit with Enter or the button (no reload thanks to .prevent), and press Escape to clear. Notice how v-model and events cooperate naturally.

Why Declarative Listeners Win

Because listeners live in the template next to the element, you can see behavior at a glance -- no hunting for addEventListener calls. Vue also removes all listeners automatically when the component unmounts, so there are no manual cleanup steps or memory leaks.

Key Takeaways

  • @event="handler" is the shorthand for v-on:event; use methods for real logic, inline expressions for trivial ones.
  • $event gives you the native event when passing extra arguments.
  • Modifiers like .prevent, .stop, .once, and .self replace boilerplate calls.
  • Key modifiers (@keyup.enter, @keydown.ctrl.s) make keyboard handling declarative.
  • Vue cleans up listeners automatically on unmount.

Next up: Computed Properties and Watchers -- deriving state efficiently and reacting to changes.

Handling Events - Vue.js | CodeYourCraft | CodeYourCraft