useWindowEvent is a hook for type‑safe subscription to native events on the global window object. It supports two forms: a single event and an events map. The hook keeps handlers fresh without reattaching listeners and cleans them up correctly on unmount. Default options: capture: false, once: false, passive: false.
// 1) Single event
function useWindowEvent<T extends UseWindowEventType>(
eventType: T,
eventHandler: UseWindowEventHandler<T>,
eventOptions?: AddEventListenerOptions,
): void;
// 2) Events map
function useWindowEvent(eventsMap: UseWindowEventMap): void;-
Parameters
eventType— window event name ('resize','scroll','keydown', etc.).eventHandler— listener; the event type is inferred automatically.eventOptions?— listener options (capture,once,passive).eventsMap— an object of the form{ type: handler | [handler, options] }.
-
Returns
void.
import { useState } from 'react';
import { useWindowEvent } from '@webeach/react-hooks/useWindowEvent';
export function ViewportWidth() {
const [width, setWidth] = useState(() => window.innerWidth);
useWindowEvent('resize', () => {
setWidth(window.innerWidth);
});
return <div>width: {width}px</div>;
}import { useWindowEvent } from '@webeach/react-hooks/useWindowEvent';
type ConfirmLeaveProps = {
enabled: boolean;
};
export function ConfirmLeave(props: ConfirmLeaveProps) {
const { enabled } = props;
useWindowEvent('beforeunload', (event) => {
if (!enabled) {
return;
}
event.preventDefault();
event.returnValue = '';
});
return null;
}import { useWindowEvent } from '@webeach/react-hooks/useWindowEvent';
export function ScrollAndHotkey() {
useWindowEvent({
scroll: [
() => {
// no preventDefault; passive=true improves scroll performance
console.debug('scrollY =', window.scrollY);
},
{ passive: true },
],
keydown: [
(event) => {
if (event.key === 'h') {
console.log('hotkey!');
}
},
{ once: true },
],
});
return null;
}-
Layout‑phase subscription
- Listeners attach/detach synchronously during the layout phase to avoid missing early events before paint.
-
Fresh handlers
- The hook keeps handlers in a “live” ref, so you can replace functions between renders without reattaching; the latest version will run.
-
When reattachment happens
- Listeners are reattached when the structure of the events map or their options (
capture/once/passive) change. Changing handler functions alone does not require reattachment.
- Listeners are reattached when the structure of the events map or their options (
-
Default options
- If no options are provided, defaults are
capture: false,once: false,passive: false.
- If no options are provided, defaults are
-
Automatic cleanup
- All subscriptions are removed automatically on unmount.
-
SSR‑safe
- There is no
windowaccess during render; subscription happens only after mount.
- There is no
- Global window events:
resize,scroll,keydown,visibilitychange,beforeunload, etc. - Scenarios where the handler changes frequently and you want to avoid reattaching listeners.
- When it’s convenient to describe multiple events with a single map.
- If React element handlers (
onClick,onChange) are sufficient — they don’t require global listeners. - For other event targets (
document, media elements,BroadcastChannel) — use dedicated hooks/wrappers (e.g.,useDOMEvent).
-
Missing
passivefor scroll- If you don’t intend to call
preventDefault, set{ passive: true }for better scroll performance.
- If you don’t intend to call
-
Expecting React synthetic events
- This hook works with native
windowevents. Types and behavior differ fromSyntheticEvent.
- This hook works with native
-
Accidental option changes
- Toggling
capture/once/passiveforces reattachment. Make sure that’s intentional.
- Toggling
-
Using
signal- The
signaloption isn’t supported; use your own cancellation if needed.
- The
Exported types
-
UseWindowEventHandler<EventType>(event: UseWindowEventInstance<EventType>) => void— type‑safe handler; the event type is inferred from the name ('keydown'→KeyboardEvent,'resize'→UIEvent/Event).
-
UseWindowEventInstance<EventType>- The corresponding event object from
WindowEventMap[EventType].
- The corresponding event object from
-
UseWindowEventMap- Mapping
{ [type]: handler | [handler, options] }to attach several listeners in one call.
- Mapping
-
UseWindowEventOptions- Listener options without
signal:{ capture?: boolean; once?: boolean; passive?: boolean }.
- Listener options without
-
UseWindowEventType- Union of all keys of
WindowEventMap.
- Union of all keys of