Files
agent-skills/skills/vue-best-practices/reference/event-once-modifier-for-single-use.md
Jason Woltje f5792c40be feat: Complete fleet — 94 skills across 10+ domains
Pulled ALL skills from 15 source repositories:
- anthropics/skills: 16 (docs, design, MCP, testing)
- obra/superpowers: 14 (TDD, debugging, agents, planning)
- coreyhaines31/marketingskills: 25 (marketing, CRO, SEO, growth)
- better-auth/skills: 5 (auth patterns)
- vercel-labs/agent-skills: 5 (React, design, Vercel)
- antfu/skills: 16 (Vue, Vite, Vitest, pnpm, Turborepo)
- Plus 13 individual skills from various repos

Mosaic Stack is not limited to coding — the Orchestrator and
subagents serve coding, business, design, marketing, writing,
logistics, analysis, and more.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 16:27:42 -06:00

4.6 KiB

title, impact, impactDescription, type, tags
title impact impactDescription type tags
Use .once Modifier for Single-Use Event Handlers LOW The .once modifier auto-removes event listeners after first trigger, preventing repeated handler calls best-practice
vue3
events
modifiers
once
event-handling

Use .once Modifier for Single-Use Event Handlers

Impact: LOW - Vue provides a .once modifier for event listeners that automatically removes the listener after it fires once. This is useful for one-time events like initialization callbacks, first-interaction tracking, or one-time animations.

Task Checklist

  • Use .once for events that should only fire once
  • Consider .once for analytics first-interaction tracking
  • Use .once for initialization events
  • Remember .once works on both native and component events

Basic Usage

Component events:

<template>
  <!-- Handler fires only on first emit, then stops listening -->
  <ChildComponent @initialized.once="handleInit" />

  <!-- First-time user interaction tracking -->
  <UserForm @submit.once="trackFirstSubmit" />
</template>

<script setup>
function handleInit(data) {
  console.log('Component initialized:', data)
  // This only runs once, even if child emits 'initialized' multiple times
}

function trackFirstSubmit() {
  analytics.track('first_form_submit')
}
</script>

Native DOM events:

<template>
  <!-- First click only -->
  <button @click.once="showWelcomeMessage">
    Click to see welcome (once)
  </button>

  <!-- First scroll only -->
  <div @scroll.once="loadMoreContent">
    Scroll to load more
  </div>
</template>

Common Use Cases

One-Time Initialization

<template>
  <ThirdPartyChart
    @ready.once="onChartReady"
    :data="chartData"
  />
</template>

<script setup>
function onChartReady(chartInstance) {
  // Store reference, configure chart
  // Only need to do this once
  chartRef.value = chartInstance
  chartInstance.setOption(customOptions)
}
</script>

First Interaction Analytics

<template>
  <article @click.once="trackEngagement">
    <h2>{{ article.title }}</h2>
    <p>{{ article.excerpt }}</p>
  </article>
</template>

<script setup>
function trackEngagement() {
  analytics.track('article_first_click', {
    articleId: article.id
  })
}
</script>

Lazy Loading Trigger

<template>
  <div
    ref="lazyContainer"
    @mouseenter.once="loadHeavyContent"
  >
    <template v-if="loaded">
      <HeavyComponent :data="data" />
    </template>
    <template v-else>
      <Placeholder />
    </template>
  </div>
</template>

<script setup>
const loaded = ref(false)
const data = ref(null)

async function loadHeavyContent() {
  data.value = await fetchData()
  loaded.value = true
}
</script>

One-Time Animation

<template>
  <Transition
    @after-enter.once="onFirstAppearance"
  >
    <div v-if="show" class="animated-content">
      Content
    </div>
  </Transition>
</template>

<script setup>
function onFirstAppearance() {
  // Track first time user sees this element
  // Won't fire again if element leaves and re-enters
}
</script>

Combining with Other Modifiers

<template>
  <!-- Once + prevent default -->
  <form @submit.once.prevent="handleFirstSubmit">
    ...
  </form>

  <!-- Once + stop propagation -->
  <div @click.once.stop="handleClick">
    ...
  </div>

  <!-- Once + key modifier -->
  <input @keyup.enter.once="submitOnFirstEnter" />
</template>

Equivalent Manual Implementation

Without .once, you'd need to manually track and remove:

<script setup>
const hasHandled = ref(false)

function handleClickManually() {
  if (hasHandled.value) return
  hasHandled.value = true

  // Do one-time action
  doSomething()
}
</script>

<template>
  <!-- Manual approach - more verbose -->
  <button @click="handleClickManually">Click</button>

  <!-- .once approach - cleaner -->
  <button @click.once="doSomething">Click</button>
</template>

When NOT to Use .once

Don't use .once when:

  • You need the event to fire multiple times
  • You want to conditionally allow repeated fires
  • The "once" logic is complex (use manual ref tracking instead)
<template>
  <!-- DON'T: User expects multiple submissions to work -->
  <form @submit.once.prevent="handleSubmit">
    ...
  </form>

  <!-- DO: Allow repeated submissions -->
  <form @submit.prevent="handleSubmit">
    ...
  </form>
</template>

Reference