Skip to content

VueJS - Events

Vue allows you to listen to DOM events using the v-on directive, or its shorthand @, and run JavaScript code when those events are triggered. This chapter covers various aspects of event handling in Vue 3.

You can use v-on:eventname or the shorthand @eventname to attach event listeners to elements.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vue 3 Click Event</title>
<script src="https://unpkg.com/vue@3"></script>
</head>
<body>
<div id="app-click">
<button v-on:click="incrementCounter">Click Me (v-on)</button>
<button @click="incrementCounter">Click Me (@)</button>
<p>Counter: {{ counter }}</p>
<button @click="greet('Hello Vue!')">Greet</button>
</div>
<script>
const { createApp, ref } = Vue;
createApp({
setup() {
const counter = ref(0);
function incrementCounter() {
counter.value++;
console.log('Counter incremented!');
}
function greet(message) {
alert(message);
}
return {
counter,
incrementCounter,
greet
};
}
}).mount('#app-click');
</script>
</body>
</html>
  • v-on:click="incrementCounter" or @click="incrementCounter" calls the incrementCounter method when the button is clicked.
  • Methods are defined within the setup() function in the Composition API.
  • You can pass arguments directly in the template, like @click="greet('Hello Vue!')".
  • If you need the original DOM event object, you can access it automatically if no arguments are passed (incrementCounter could accept event as its first argument), or explicitly pass it using the special $event variable: @click="handleEvent($event, 'some value')".

Example: Mouse Events (mouseover, mouseout)

Section titled “Example: Mouse Events (mouseover, mouseout)”
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vue 3 Mouse Events</title>
<script src="https://unpkg.com/vue@3"></script>
<style>
.hover-box {
width: 150px;
height: 100px;
border: 1px solid black;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
transition: background-color 0.3s ease;
}
</style>
</head>
<body>
<div id="app-mouse">
<div
class="hover-box"
:style="{ backgroundColor: boxColor }"
@mouseover="changeColor('lightgreen')"
@mouseout="changeColor('lightblue')">
Hover over me!
</div>
<p>Current Box Color: {{ boxColor }}</p>
</div>
<script>
const { createApp, ref } = Vue;
createApp({
setup() {
const boxColor = ref('lightblue'); // Initial color
function changeColor(newColor) {
boxColor.value = newColor;
}
return {
boxColor,
changeColor
};
}
}).mount('#app-mouse');
</script>
</body>
</html>
  • The div listens for mouseover and mouseout events.
  • The changeColor method is called with the desired color string when the events occur.
  • The background color is dynamically bound to the boxColor reactive variable using :style.

Vue provides event modifiers to handle common tasks directly in the template. Modifiers are suffixes added after the event name, separated by a dot (.):

  • .stop: Calls event.stopPropagation().
  • .prevent: Calls event.preventDefault().
  • .capture: Adds the event listener in capture mode.
  • .self: Only triggers the handler if the event originated from this element itself (not from a child element).
  • .once: Triggers the handler at most once.
  • .passive: Improves performance on mobile devices for scroll events (corresponds to addEventListener’s passive option).
<div id="app-modifiers">
<!-- Prevent default form submission -->
<form @submit.prevent="onSubmit">
<input type="text" placeholder="Enter something">
<button type="submit">Submit (No Page Reload)</button>
</form>
<!-- Button that can only be clicked once -->
<button @click.once="doOnce">Click Me Only Once</button>
<p>Once Click Count: {{ onceCount }}</p>
</div>
<script>
const { createApp, ref } = Vue;
createApp({
setup() {
const onceCount = ref(0);
function onSubmit() {
alert('Form submitted via Vue (page did not reload)!');
}
function doOnce() {
onceCount.value++;
alert('This alert appears only once!');
}
return { onSubmit, doOnce, onceCount };
}
}).mount('#app-modifiers');
</script>

.prevent stops the default form submission behavior (page reload). .once ensures the doOnce method is called only the first time the button is clicked.

Vue allows you to trigger event handlers only when specific keys are pressed using key modifiers.

  • .enter
  • .tab
  • .delete (captures both ‘Delete’ and ‘Backspace’ keys)
  • .esc
  • .space
  • .up, .down, .left, .right
  • System Modifiers: .ctrl, .alt, .shift, .meta (Command key on Mac, Windows key on Windows)
<div id="app-keys">
<label>Submit on Enter:</label>
<input type="text" v-model="message" @keyup.enter="submitMessage" placeholder="Type and press Enter">
<p>Submitted: {{ submittedMessage }}</p>
</div>
<script>
const { createApp, ref } = Vue;
createApp({
setup() {
const message = ref('');
const submittedMessage = ref('');
function submitMessage() {
submittedMessage.value = message.value;
message.value = ''; // Clear input
alert('Message submitted!');
}
return { message, submittedMessage, submitMessage };
}
}).mount('#app-keys');
</script>

The submitMessage method will only be called when the user releases the ‘Enter’ key while focused on the input field.

Custom Events (Child-to-Parent Communication)

Section titled “Custom Events (Child-to-Parent Communication)”

Components can emit custom events using the $emit method. Parent components can listen for these events using v-on or @.

<div id="app-custom-event">
<p>Selected Language: {{ selectedLanguage || 'None' }}</p>
<!-- Child component emitting 'language-selected' event -->
<language-selector
:languages="availableLanguages"
@language-selected="handleLanguageSelection">
</language-selector>
</div>
<script>
const { createApp, ref } = Vue;
const app = createApp({
setup() {
const selectedLanguage = ref('');
const availableLanguages = ref(['JavaScript', 'Python', 'Java', 'C#']);
function handleLanguageSelection(language) {
selectedLanguage.value = language;
console.log(`Parent received selected language: ${language}`);
}
return {
selectedLanguage,
availableLanguages,
handleLanguageSelection
};
}
});
// Child Component: LanguageSelector
app.component('language-selector', {
props: {
languages: { type: Array, required: true }
},
emits: ['language-selected'], // Best practice: declare emitted events
template: `
<div>
<button
v-for="lang in languages"
:key="lang"
@click="selectLanguage(lang)"
style="margin: 5px; font-size: 1em;">
{{ lang }}
</button>
</div>
`,
methods: {
selectLanguage(lang) {
// Emit the event with the selected language as payload
this.$emit('language-selected', lang);
}
}
// In Composition API setup for component:
/*
setup(props, { emit }) {
function selectLanguage(lang) {
emit('language-selected', lang);
}
return { selectLanguage };
}
*/
});
app.mount('#app-custom-event');
</script>
  • The language-selector child component receives a list of languages via props.
  • When a button in the child component is clicked, its selectLanguage method calls this.$emit('language-selected', lang). This sends the language-selected event up to the parent, carrying the chosen language (lang) as data (payload).
  • The parent component listens for this event using @language-selected="handleLanguageSelection" on the <language-selector> tag.
  • The parent’s handleLanguageSelection method receives the payload (the selected language) and updates the selectedLanguage state.
  • Declaring emitted events with emits: ['language-selected'] in the child component is recommended in Vue 3 for clarity and potential future optimizations.

Event handling is fundamental to building interactive applications. Vue’s system with v-on, modifiers, and $emit provides a powerful and declarative way to manage user interactions and component communication.