or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

async-operations.mddata-structures.mddom-interactions.mdeffects.mdindex.mdperformance.mdspecialized-hooks.mdstate-management.mdstorage.mdtimers.md
tile.json

dom-interactions.mddocs/

DOM Interactions

Comprehensive hooks for DOM events, user interactions, measurements, viewport tracking, and browser API integration.

Capabilities

Event Management

useClickAway

Triggers callback when clicking outside target element(s), commonly used for modals and dropdowns.

/**
 * Triggers callback when clicking outside target element(s)
 * @param onClickAway - Callback function to execute on outside click
 * @param target - Element(s) to monitor for outside clicks
 * @param eventName - DOM event name(s) to listen for (default: 'click')
 */
function useClickAway<T extends Event = Event>(
  onClickAway: (event: T) => void,
  target: BasicTarget | BasicTarget[],
  eventName?: DocumentEventKey | DocumentEventKey[]
): void;

type BasicTarget<T = Element> = (() => T | null) | T | null | MutableRefObject<T>;
type DocumentEventKey = keyof DocumentEventMap;

Usage Example:

import { useClickAway } from 'ahooks';
import { useRef, useState } from 'react';

function Dropdown() {
  const [visible, setVisible] = useState(false);
  const ref = useRef<HTMLDivElement>(null);
  
  useClickAway(() => {
    setVisible(false);
  }, ref);
  
  return (
    <div ref={ref}>
      <button onClick={() => setVisible(!visible)}>
        Toggle Dropdown
      </button>
      {visible && (
        <ul className="dropdown">
          <li>Option 1</li>
          <li>Option 2</li>
          <li>Option 3</li>
        </ul>
      )}
    </div>
  );
}

useEventListener

Manages event listeners with automatic cleanup and support for multiple target types.

/**
 * Manages event listeners with automatic cleanup
 * Multiple overloads for different target types
 */
function useEventListener<K extends keyof HTMLElementEventMap>(
  eventName: K,
  handler: (ev: HTMLElementEventMap[K]) => void,
  options?: Options<HTMLElement>
): void;

function useEventListener<K extends keyof ElementEventMap>(
  eventName: K,
  handler: (ev: ElementEventMap[K]) => void,
  options?: Options<Element>
): void;

function useEventListener<K extends keyof DocumentEventMap>(
  eventName: K,
  handler: (ev: DocumentEventMap[K]) => void,
  options?: Options<Document>
): void;

function useEventListener<K extends keyof WindowEventMap>(
  eventName: K,
  handler: (ev: WindowEventMap[K]) => void,
  options?: Options<Window>
): void;

interface Options<T> {
  /** Target element, document, window, or ref */
  target?: BasicTarget<T>;
  /** Event listener options */
  capture?: boolean;
  once?: boolean;
  passive?: boolean;
}

Usage Example:

import { useEventListener } from 'ahooks';
import { useRef } from 'react';

function KeyboardHandler() {
  const [lastKey, setLastKey] = useState('');
  const divRef = useRef<HTMLDivElement>(null);
  
  // Listen to document keydown
  useEventListener('keydown', (event) => {
    setLastKey(event.key);
  }, {
    target: document
  });
  
  // Listen to specific element click
  useEventListener('click', (event) => {
    console.log('Div clicked:', event);
  }, {
    target: divRef
  });
  
  // Listen to window resize
  useEventListener('resize', () => {
    console.log('Window resized');
  }, {
    target: window
  });
  
  return (
    <div ref={divRef}>
      <p>Last key pressed: {lastKey}</p>
      <p>Click this div or press any key</p>
    </div>
  );
}

User Interactions

useHover

Tracks hover state of an element with enter/leave callbacks.

/**
 * Tracks hover state of an element
 * @param target - Element to track hover state for
 * @param options - Configuration with hover callbacks
 * @returns Boolean indicating if element is currently hovered
 */
function useHover(target: BasicTarget, options?: Options): boolean;

interface Options {
  /** Callback when mouse enters */
  onEnter?: () => void;
  /** Callback when mouse leaves */
  onLeave?: () => void;
  /** Callback when hover state changes */
  onChange?: (isHovering: boolean) => void;
}

Usage Example:

import { useHover } from 'ahooks';
import { useRef } from 'react';

function HoverCard() {
  const ref = useRef<HTMLDivElement>(null);
  
  const isHovering = useHover(ref, {
    onEnter: () => console.log('Mouse entered'),
    onLeave: () => console.log('Mouse left'),
    onChange: (hovering) => console.log('Hover state:', hovering)
  });
  
  return (
    <div 
      ref={ref}
      style={{
        padding: '20px',
        backgroundColor: isHovering ? 'lightblue' : 'lightgray',
        transition: 'background-color 0.3s'
      }}
    >
      {isHovering ? 'Currently hovering!' : 'Hover me!'}
    </div>
  );
}

useFocusWithin

Tracks focus within element (like CSS :focus-within selector) with focus/blur callbacks.

/**
 * Tracks focus within element (like :focus-within CSS selector)
 * @param target - Element to track focus within
 * @param options - Configuration with focus callbacks
 * @returns Boolean indicating if any descendant element has focus
 */
function useFocusWithin(target: BasicTarget, options?: Options): boolean;

interface Options {
  /** Callback when focus enters the element or its children */
  onFocus?: (e: FocusEvent) => void;
  /** Callback when focus leaves the element and its children */
  onBlur?: (e: FocusEvent) => void;
  /** Callback when focus-within state changes */
  onChange?: (isFocusWithin: boolean) => void;
}

useKeyPress

Handles keyboard key press events with flexible key filtering and target options.

/**
 * Handles keyboard key press events with flexible filtering
 * @param keyFilter - Key(s) to listen for or filter function
 * @param eventHandler - Handler function when matching keys are pressed
 * @param options - Configuration options
 */
function useKeyPress(
  keyFilter: KeyFilter,
  eventHandler: (event: KeyboardEvent, key: KeyType) => void,
  options?: Options
): void;

type KeyFilter = KeyType | KeyType[] | ((event: KeyboardEvent) => boolean);
type KeyType = number | string;
type KeyEvent = 'keydown' | 'keyup';

interface Options {
  /** Events to listen for (default: ['keydown']) */
  events?: KeyEvent[];
  /** Target element (default: document) */
  target?: BasicTarget;
  /** Require exact match for modifier keys (default: false) */
  exactMatch?: boolean;
  /** Use capture phase (default: false) */
  useCapture?: boolean;
}

Usage Example:

import { useKeyPress } from 'ahooks';

function KeyboardShortcuts() {
  const [message, setMessage] = useState('');
  
  // Listen for specific key
  useKeyPress('Enter', (event) => {
    setMessage('Enter pressed!');
  });
  
  // Listen for multiple keys
  useKeyPress(['ctrl.s', 'cmd.s'], (event) => {
    event.preventDefault();
    setMessage('Save shortcut pressed!');
  });
  
  // Listen for arrow keys
  useKeyPress(['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight'], (event, key) => {
    setMessage(`Arrow key pressed: ${key}`);
  });
  
  // Custom key filter function
  useKeyPress((event) => event.key >= '0' && event.key <= '9', (event) => {
    setMessage(`Number pressed: ${event.key}`);
  });
  
  return (
    <div>
      <p>Press Enter, Ctrl+S, arrow keys, or number keys</p>
      <p>Last action: {message}</p>
    </div>
  );
}

useLongPress

Handles long press gestures with customizable timing and movement threshold.

/**
 * Handles long press gestures
 * @param onLongPress - Callback when long press is detected
 * @param target - Element to attach long press to
 * @param options - Configuration options
 */
function useLongPress(
  onLongPress: (event: EventType) => void,
  target: BasicTarget,
  options?: Options
): void;

type EventType = MouseEvent | TouchEvent;

interface Options {
  /** Long press duration in ms (default: 350) */
  delay?: number;
  /** Movement threshold to cancel long press */
  moveThreshold?: { x?: number; y?: number };
  /** Callback for normal click */
  onClick?: (event: EventType) => void;
  /** Callback when long press ends */
  onLongPressEnd?: (event: EventType) => void;
}

Element Measurements

useSize

Tracks element size changes using ResizeObserver.

/**
 * Tracks element size changes using ResizeObserver
 * @param target - Element to track size for
 * @returns Object with width and height, or undefined if element not found
 */
function useSize(target: BasicTarget): Size | undefined;

interface Size {
  width: number;
  height: number;
}

Usage Example:

import { useSize } from 'ahooks';
import { useRef } from 'react';

function ResizableDiv() {
  const ref = useRef<HTMLDivElement>(null);
  const size = useSize(ref);
  
  return (
    <div>
      <div 
        ref={ref}
        style={{
          width: '50%',
          height: '200px',
          backgroundColor: 'lightblue',
          resize: 'both',
          overflow: 'auto'
        }}
      >
        Resize me!
      </div>
      {size && (
        <p>
          Size: {Math.round(size.width)} x {Math.round(size.height)}
        </p>
      )}
    </div>
  );
}

useScroll

Tracks scroll position of an element or window.

/**
 * Tracks scroll position of element or window
 * @param target - Element to track scroll for (default: document)
 * @param shouldUpdate - Function to determine if position should update
 * @returns Object with scroll position or undefined
 */
function useScroll(
  target?: BasicTarget, 
  shouldUpdate?: (position: Position) => boolean
): Position | undefined;

interface Position {
  left: number;
  top: number;
}

useInViewport

Tracks element visibility in viewport using Intersection Observer.

/**
 * Tracks element visibility in viewport using Intersection Observer
 * @param target - Element(s) to track viewport intersection
 * @param options - Intersection Observer options
 * @returns Array with visibility boolean and intersection ratio
 */
function useInViewport(
  target: BasicTarget | BasicTarget[], 
  options?: Options
): [boolean?, number?];

interface Options {
  /** Root margin for intersection detection */
  rootMargin?: string;
  /** Threshold(s) for intersection detection */
  threshold?: number | number[];
  /** Root element for intersection (default: viewport) */
  root?: BasicTarget<Element>;
  /** Callback when intersection changes */
  callback?: (entry: IntersectionObserverEntry) => void;
}

Mouse Tracking

useMouse

Tracks comprehensive mouse position and element relationship data.

/**
 * Tracks comprehensive mouse position data
 * @param target - Element to track mouse relative to (optional)
 * @returns Object with detailed cursor position information
 */
function useMouse(target?: BasicTarget): CursorState;

interface CursorState {
  /** Screen X coordinate */
  screenX: number;
  /** Screen Y coordinate */
  screenY: number;
  /** Client X coordinate (relative to viewport) */
  clientX: number;
  /** Client Y coordinate (relative to viewport) */
  clientY: number;
  /** Page X coordinate (including scroll) */
  pageX: number;
  /** Page Y coordinate (including scroll) */
  pageY: number;
  /** X coordinate relative to target element */
  elementX: number;
  /** Y coordinate relative to target element */
  elementY: number;
  /** Target element height */
  elementH: number;
  /** Target element width */
  elementW: number;
  /** Target element X position */
  elementPosX: number;
  /** Target element Y position */
  elementPosY: number;
}

Fullscreen Management

useFullscreen

Manages fullscreen state for elements with comprehensive control actions.

/**
 * Manages fullscreen state for elements
 * @param target - Element to make fullscreen
 * @param options - Configuration options
 * @returns Array with fullscreen state and control actions
 */
function useFullscreen(
  target: BasicTarget, 
  options?: Options
): [boolean, FullscreenActions];

interface Options {
  /** Callback when exiting fullscreen */
  onExit?: () => void;
  /** Callback when entering fullscreen */
  onEnter?: () => void;
  /** Enable page-level fullscreen (CSS-based) */
  pageFullscreen?: boolean | PageFullscreenOptions;
}

interface PageFullscreenOptions {
  className?: string;
  zIndex?: number;
}

interface FullscreenActions {
  /** Enter fullscreen mode */
  enterFullscreen: () => void;
  /** Exit fullscreen mode */
  exitFullscreen: () => void;
  /** Toggle fullscreen mode */
  toggleFullscreen: () => void;
  /** Whether fullscreen is supported */
  isEnabled: boolean;
}

Text Selection

useTextSelection

Tracks text selection within target element or document.

/**
 * Tracks text selection within target element or document
 * @param target - Element to track text selection within (optional)
 * @returns Object with selection text and position information
 */
function useTextSelection(target?: BasicTarget): TextSelectionState;

interface TextSelectionState {
  /** Selected text content */
  text: string;
  /** Selection left position */
  left: number;
  /** Selection top position */
  top: number;
  /** Selection height */
  height: number;
  /** Selection width */
  width: number;
}

DOM Mutation Observation

useMutationObserver

Observes DOM mutations using MutationObserver API.

/**
 * Observes DOM mutations using MutationObserver
 * @param target - Element(s) to observe for mutations
 * @param callback - Function called when mutations occur
 * @param options - MutationObserver configuration options
 */
function useMutationObserver(
  target: BasicTarget | BasicTarget[],
  callback: MutationCallback,
  options?: MutationObserverInit
): void;

// MutationCallback and MutationObserverInit are standard DOM types

Usage Example:

import { useMutationObserver } from 'ahooks';
import { useRef, useState } from 'react';

function MutationTracker() {
  const ref = useRef<HTMLDivElement>(null);
  const [mutations, setMutations] = useState<string[]>([]);
  
  useMutationObserver(
    ref,
    (mutationsList) => {
      const newMutations = mutationsList.map(mutation => {
        return `${mutation.type}: ${mutation.target.nodeName}`;
      });
      setMutations(prev => [...prev, ...newMutations].slice(-10));
    },
    {
      childList: true,
      subtree: true,
      attributes: true,
      attributeOldValue: true
    }
  );
  
  const addChild = () => {
    if (ref.current) {
      const div = document.createElement('div');
      div.textContent = `Child ${Date.now()}`;
      ref.current.appendChild(div);
    }
  };
  
  return (
    <div>
      <button onClick={addChild}>Add Child</button>
      <div ref={ref} style={{ border: '1px solid black', padding: '10px' }}>
        Mutations will be tracked here
      </div>
      <ul>
        {mutations.map((mutation, index) => (
          <li key={index}>{mutation}</li>
        ))}
      </ul>
    </div>
  );
}

Common Types

// React ref types
type MutableRefObject<T> = import('react').MutableRefObject<T>;

// Target element types
type BasicTarget<T = Element> = (() => T | null) | T | null | MutableRefObject<T>;

// DOM event map types
type DocumentEventKey = keyof DocumentEventMap;
type WindowEventKey = keyof WindowEventMap;