FluentUI Compat

Home > @cascadiacollections/fluentui-compat > useOnEvent

useOnEvent() function

Hook to attach event listeners to window or document with automatic cleanup.

This hook provides a declarative way to manage event listeners that: - **Automatically cleans up**: Removes listeners on unmount or when dependencies change - **Type safe**: Full TypeScript support for event types - **Performance optimized**: Uses stable callbacks to prevent re-registration - **SSR safe**: Handles server-side rendering gracefully - **Flexible target**: Supports window, document, or any event target

**Common use cases**: - Window resize, scroll events - Document click/keydown for global interactions - Custom events on event targets - Keyboard shortcuts - Outside click detection

Signature:

export declare function useOnEvent<K extends keyof WindowEventMap>(target: Window | null | undefined, eventName: K, handler: (event: WindowEventMap[K]) => void, options?: boolean | AddEventListenerOptions): void;

Parameters

Parameter

Type

Description

target

Window | null | undefined

The event target (window, document, or EventTarget), or null to skip

eventName

K

The name of the event to listen for

handler

(event: WindowEventMap[K]) => void

The event handler callback

options

boolean | AddEventListenerOptions

(Optional) Optional event listener options (capture, passive, once)

Returns:

void

Example 1

// Window resize listener
function ResponsiveComponent() {
  const [width, setWidth] = useState(window.innerWidth);

  useOnEvent(window, 'resize', () => {
    setWidth(window.innerWidth);
  });

  return <div>Window width: {width}px</div>;
}

Example 2

// Keyboard shortcuts
function KeyboardShortcuts() {
  const [lastKey, setLastKey] = useState('');

  useOnEvent(document, 'keydown', (event: KeyboardEvent) => {
    if (event.ctrlKey && event.key === 's') {
      event.preventDefault();
      console.log('Save shortcut triggered');
    }
    setLastKey(event.key);
  });

  return <div>Last key pressed: {lastKey}</div>;
}

Example 3

// Outside click detection
function Dropdown() {
  const [isOpen, setIsOpen] = useState(false);
  const dropdownRef = useRef<HTMLDivElement>(null);

  useOnEvent(document, 'mousedown', (event: MouseEvent) => {
    if (isOpen && dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) {
      setIsOpen(false);
    }
  });

  return (
    <div ref={dropdownRef}>
      <button onClick={() => setIsOpen(!isOpen)}>Toggle</button>
      {isOpen && <div>Dropdown content</div>}
    </div>
  );
}

Example 4

// With event options (passive for scroll performance)
function ScrollTracker() {
  const [scrollY, setScrollY] = useState(0);

  useOnEvent(
    window,
    'scroll',
    () => {
      setScrollY(window.scrollY);
    },
    { passive: true } // Improves scroll performance
  );

  return <div>Scroll position: {scrollY}px</div>;
}

Example 5

// Conditional event listening
function ConditionalListener({ shouldListen }: { shouldListen: boolean }) {
  const [clicks, setClicks] = useState(0);

  // Pass null to skip event listener registration
  useOnEvent(
    shouldListen ? document : null,
    'click',
    () => setClicks(c => c + 1)
  );

  return <div>Document clicks: {clicks}</div>;
}

Example 6

// Custom events
function CustomEventListener() {
  const [data, setData] = useState<any>(null);

  useOnEvent(window, 'my-custom-event', (event: Event) => {
    setData((event as CustomEvent).detail);
  });

  return <div>Custom event data: {JSON.stringify(data)}</div>;
}
  • Edit this page
In this article
Back to top FluentUI React complimentary components and utilities focused on render performance