#5620·vueuse

BUG | `onKeyStroke()` | Registers a capture listener when `passive: true`

Author: danielvyCreated Sep 4, 2026Updated Sep 4, 2026
Labelspending triage

Describe the bug

Description

Passing passive: true to onKeyStroke() unexpectedly registers the event listener in the capture phase. Consequently, a descendant cannot prevent the handler from running with event.stopPropagation().

OnKeyStrokeOptions.passive indicates that it controls whether the listener is passive. The resulting listener should therefore be registered with {passive: true}, without changing its propagation phase.

Expected behavior

The input handler calls stopPropagation(), so the ancestor's onKeyStroke() handler should not run.

Actual behavior

The ancestor handler runs before the input handler: KeyboardEvent.eventPhase === 1 identifies the capturing phase.

Suspected cause

onKeyStroke() passes the passive boolean directly as the listener options:

return useEventListener(target, eventName, listener, passive);

useEventListener() correctly forwards that value to the native API:

el.addEventListener(event, listener, options);

In the native addEventListener() API, a boolean options argument represents useCapture. Thus, passive: true becomes a capture listener instead of a passive listener.

Passing an options object would preserve the documented meaning:

return useEventListener(target, eventName, listener, {passive});

Reproduction

playground.vueuse.org

System Info

System:
  OS: macOS 26.6.2
  CPU: (10) arm64 Apple M1 Pro
  Memory: 119.45 MB / 16.00 GB
  Shell: 5.9 - /bin/zsh
Binaries:
  Node: 24.19.0
  npm: 12.0.2
Browsers:
  Firefox: 154.0.1
  Safari: 26.6.2
npmPackages:
  @vueuse/core: ^14.4.0 => 14.4.0
  vue: ^3.5.40 => 3.5.42

Used Package Manager

npm

Validations