Vue · Lifecycle

VUE0025Prefer VueUse event listener cleanup

Finds Vue scopes that manually pair DOM event listener setup and cleanup when VueUse is already available.

Why it happens

DOM listeners are lifecycle resources. Keeping setup and disposal behind a composable makes repeated watcher runs, component unmounts, and composable scope disposal harder to drift apart.

Fix

Use VueUse useEventListener() for DOM listeners. In watcher callbacks, keep the returned stop handle in watcher cleanup when each watcher run owns a fresh listener.

Example

Use VueUse for watcher-owned listeners

Before

watch(active, (_value, _oldValue, onCleanup) => {
  const el = document.querySelector('.target')
  if (!el) return
  const onEnd = () => el.classList.remove('active')
  el.addEventListener('animationend', onEnd, { once: true })
  onCleanup(() => el.removeEventListener('animationend', onEnd))
})

After

watch(active, (_value, _oldValue, onCleanup) => {
  const el = document.querySelector('.target')
  if (!el) return
  const stop = useEventListener(el, 'animationend', () => {
    el.classList.remove('active')
  }, { once: true })
  onCleanup(stop)
})

Verify the fix

Run only this rule after editing so the report stays focused on the diagnostic you are closing:

pnpm vite-doctor . --framework vue --rules vue/lifecycle/prefer-use-event-listener
Copyright © 2026