Vue Event Modifiers

Event modifiers are dot-suffixes added to v-on bindings that handle common event-handling chores, like preventing default browser behavior, directly in the template.

What Are Event Modifiers

Without modifiers, tasks like calling event.preventDefault() or event.stopPropagation() have to happen inside the handler function itself, mixing DOM plumbing in with your actual logic. Event modifiers move that plumbing into the template as a dot-suffix on the event name, keeping methods focused purely on what should happen.

Preventing a form's default submit

<div id="app">
  <form @submit.prevent="onSubmit">
    <input v-model="email" placeholder="Email" />
    <button type="submit">Subscribe</button>
  </form>
  <p v-if="submitted">Thanks, {{ email }}!</p>
</div>

<script>
const app = Vue.createApp({
  data() {
    return { email: '', submitted: false }
  },
  methods: {
    onSubmit() {
      this.submitted = true
    }
  }
})
app.mount('#app')
</script>

.stop and .once

.stop calls event.stopPropagation(), preventing the event from bubbling up to parent elements, which is useful when a nested clickable element shouldn't also trigger a handler on its container. .once removes the listener automatically after it fires a single time, handy for things like a one-time dismissible banner.

Using .stop and .once together

<div id="app">
  <div @click="closePanel" class="overlay">
    <div @click.stop="noop" class="panel">
      <p>Click outside this box to close.</p>
      <button @click.once="claimBonus">Claim welcome bonus</button>
    </div>
  </div>
</div>

<script>
const app = Vue.createApp({
  methods: {
    closePanel() {
      console.log('Panel closed')
    },
    noop() {},
    claimBonus() {
      console.log('Bonus claimed - this only ever runs once')
    }
  }
})
app.mount('#app')
</script>
  • .prevent - calls event.preventDefault()
  • .stop - calls event.stopPropagation()
  • .self - only triggers if the event originated on the element itself, not a child
  • .capture - uses the capture phase instead of the bubble phase
  • .once - the listener fires at most one time
  • .passive - tells the browser the handler won't call preventDefault, improving scroll performance
Note: Modifiers chain together, so @click.stop.prevent is completely valid and does exactly what it looks like: stop propagation and prevent the default action, both from one attribute.

Key Modifiers

Keyboard events can be filtered down to a specific key using a key modifier, so a handler only fires when that key was the one pressed. This avoids the common pattern of checking event.key manually inside every keyup or keydown handler. System modifier keys like ctrl, alt, shift, and meta can also be combined onto other events, including click.

ModifierTriggers on
.enterthe Enter key
.escthe Escape key
.tabthe Tab key
.deleteDelete or Backspace
.spacethe Space bar
.ctrl / .alt / .shift / .metaheld together with another event, e.g. @click.ctrl

Enter to search, Ctrl+Click to open in a new context

<div id="app">
  <input
    v-model="query"
    @keyup.enter="runSearch"
    placeholder="Press Enter to search"
  />
  <a href="#" @click.ctrl.prevent="openInNewTab">Docs</a>
</div>

<script>
const app = Vue.createApp({
  data() {
    return { query: '' }
  },
  methods: {
    runSearch() {
      console.log('Searching for:', this.query)
    },
    openInNewTab() {
      console.log('Ctrl+Click detected, opening in a new tab')
    }
  }
})
app.mount('#app')
</script>
Note: Order matters for a couple of these. @click.prevent.self prevents the default for every click within the element, while @click.self.prevent only prevents the default when the click originated on the element itself. Also avoid combining .passive with .prevent on the same binding — the browser will ignore the preventDefault call and typically emit a console warning.

Exercise: Vue Event Modifiers

What does the .prevent modifier do when added to an event listener?