Edit tutorial

useOn() / useOnDocument() / useOnWindow()

Use useOn() / useOnDocument() / useOnWindow() to programmatically set up listeners on host elements. This is useful when you are creating custom APIs and don't have access to place these events in the JSX or if the events are not known ahead of time, such as if they are created based on component props.

Each hook also accepts an optional third argument for listener options:

  • { passive: true } for passive listeners such as touchmove or scroll when the callback does not need to call preventDefault().
  • { capture: true } to run the listener in the capture phase.
  • { preventdefault: true } to have Qwik call event.preventDefault() before your handler runs.
  • { stoppropagation: true } to have Qwik call event.stopPropagation() before your handler runs.

preventdefault and stoppropagation mirror the JSX preventdefault:event and stoppropagation:event attributes. Avoid combining passive: true with preventdefault: true, since passive listeners cannot prevent the browser default.

Most of the time, JSX event handlers are still the best choice:

<button onClick$={() => count.value++}>Increment</button>

Reach for useOn() when the event registration should live inside a reusable hook or helper instead of inside the template. In that case, useOn() lets you keep the listener lazy and colocated with the logic that needs it.

When To Use Each Hook

  • useOn() attaches to the current component's host element.
  • useOnDocument() listens on document.
  • useOnWindow() listens on window.

This means useOn() is a good fit for component-local behavior, while useOnDocument() and useOnWindow() are better for global concerns like keyboard shortcuts, resize handling, or document-level pointer tracking.

Example

This custom hook adds a keyboard shortcut without rendering any markup of its own:

import { $, useOnDocument } from '@qwik.dev/core';
 
export function useEscape(onEscape$: () => void) {
  useOnDocument(
    'keydown',
    $((event) => {
      if ((event as KeyboardEvent).key === 'Escape') {
        onEscape$();
      }
    })
  );
}

That is the kind of scenario where useOn*() is usually clearer than passing event handlers through several layers of JSX.

Event Modifiers

The same options work with useOnDocument() and useOnWindow():

useOn(
  'click',
  $(() => {
    // Runs during capture and stops later bubbling handlers.
  }),
  { capture: true, stoppropagation: true }
);

Example

The example on the right shows how to use useOn() method. Duplicate the code to explore how to use useOnDocument() / useOnWindow() and how they behave differently.

Building preview

Refreshing App output

Compiling the latest client and SSR result for your current code.

No console activity yet

Interact with the app or trigger a render to see client and SSR messages here.