Event Handling
|
This section documents the current Vue 3.x release line as published at
the official Vue.js documentation, which is the reference these pages are written and
verified against. No specific patch version is pinned. The Composition API with This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production, since Vue and its ecosystem iterate quickly. This section’s bibliography lists the reference material consulted while preparing these pages. |
Vue listens to DOM events with the v-on directive, almost always written with its @ shorthand. The
handler is either an inline expression or a method, and a chain of modifiers absorbs the boilerplate
that normally clutters an event callback. The reference for everything on this page is
Event Handling.
v-on and the @ shorthand
@click="handler" is shorthand for v-on:click="handler". The name after the colon (or @) is the native
DOM event type — click, input, submit, keyup, pointerdown, and so on. Components can also emit
their own events; that case is in Component Events and v-model.
<script setup>
import { ref } from 'vue'
const count = ref(0)
</script>
<template>
<button @click="count++">Add one</button>
<p>Clicked {{ count }} times</p>
</template>
Inline vs. method handlers
An inline handler is a JavaScript statement — good for something trivial. A method handler is the name of a function (or a property path); Vue calls it with the native event as the only argument. See Method Handlers and Inline Handlers.
<script setup>
import { ref } from 'vue'
const count = ref(0)
function increment(event) {
count.value++
console.log(event.currentTarget.tagName) // "BUTTON"
}
</script>
<template>
<!-- inline: a statement -->
<button @click="count++">inline</button>
<!-- method: receives the native event -->
<button @click="increment">method</button>
</template>
Reaching the native event
In an inline handler the native event is available as the special $event variable; alternatively write an
arrow function and name the parameter. Both let you pass extra arguments alongside the event. See
Accessing
Event Argument in Inline Handlers.
<template>
<!-- $event -->
<input @input="text = $event.target.value">
<!-- arrow function -->
<input @input="(e) => text = e.target.value">
<!-- a value plus the event -->
<button @click="save('draft', $event)">Save</button>
</template>
Event modifiers
Modifiers appended to the event handle the common DOM calls for you, so the method stays about logic. The
full set is .stop, .prevent, .self, .capture, .once, and .passive; see
Event Modifiers.
<template>
<!-- event.stopPropagation() -->
<a @click.stop="onClick">stop</a>
<!-- event.preventDefault() -->
<form @submit.prevent="onSubmit">prevent</form>
<!-- chained: both, in order -->
<a @click.stop.prevent="onClick">both</a>
<!-- only when event.target is this element, not a descendant -->
<div @click.self="onClick">self</div>
<!-- listener attached in the capture phase -->
<div @click.capture="onClick">capture</div>
<!-- fires at most once, then the listener is removed -->
<button @click.once="onClick">once</button>
<!-- addEventListener(..., { passive: true }); cannot call preventDefault() -->
<div @scroll.passive="onScroll">passive</div>
</template>
Modifiers are order-sensitive because the generated code runs in the order written: @click.prevent.self
prevents the default on the element and its children, while @click.self.prevent only prevents it when the
click is on the element itself.
.passive and .prevent contradict each other — .prevent is ignored on a passive listener and the
browser logs a warning. Use .passive for touch and scroll listeners where you never need to cancel the
default.
|
Key modifiers
For keyboard events, a modifier restricts the handler to a key. .enter, .tab, .delete (Delete and
Backspace), .esc, .space, .up, .down, .left, and .right are named aliases; any other
KeyboardEvent.key value works in kebab-case (@keyup.page-down, @keyup.arrow-up). See
Key Modifiers.
<template>
<input @keyup.enter="submit">
<input @keyup.esc="clear">
<input @keyup.page-down="onPageDown">
</template>
System modifier keys
.ctrl, .alt, .shift, and .meta require that modifier key to be held when the event fires. They pair
with a key event or a mouse event, and unlike the key aliases they match even if other keys are also down.
See System Modifier Keys.
<template>
<input @keyup.alt.enter="send">
<div @click.ctrl="onCtrlClick">Ctrl-click me</div>
</template>
.exact
.exact pins down which system modifiers may be pressed — no more, no less. See
the .exact modifier.
<template>
<!-- also fires when Alt or Shift is held too -->
<button @click.ctrl="onClick">A</button>
<!-- fires only when Ctrl and no other system modifier is held -->
<button @click.ctrl.exact="onClick">B</button>
<!-- fires only when no system modifier at all is held -->
<button @click.exact="onClick">C</button>
</template>
Mouse-button modifiers
.left, .right, and .middle restrict a mouse handler to a single button. See
Mouse Button Modifiers.
<template>
<button @mousedown.middle="paste">middle-click paste</button>
<div @click.right="onContextMenu">right-click</div>
</template>
See also
-
Component Events and v-model — listening to events a child component emits with
defineEmits. -
Form Input Bindings —
v-model, which wraps@input/@changefor form controls. -
Watchers — reacting to state changes rather than to DOM events.
-
React Reference — React’s synthetic-event system, for contrast.