typescriptadvanced

useSelectionRange Hook

Tracks user text selection within a container, returning selected text and range coordinates.

typescript
import { useState, useEffect, useRef, RefObject } from 'react';

interface Selection {
  text: string;
  rect: DOMRect | null;
}

export function useSelectionRange<T extends HTMLElement>(): [RefObject<T | null>, Selection] {
  const ref = useRef<T | null>(null);
  const [selection, setSelection] = useState<Selection>({ text: '', rect: null });

  useEffect(() => {
    const handler = () => {
      const sel = window.getSelection();
      if (!sel || sel.isCollapsed || !ref.current) {
        setSelection({ text: '', rect: null });
        return;
      }

      const range = sel.getRangeAt(0);
      if (ref.current.contains(range.commonAncestorContainer)) {
        setSelection({
          text: sel.toString(),
          rect: range.getBoundingClientRect(),
        });
      }
    };

    document.addEventListener('selectionchange', handler);
    return () => document.removeEventListener('selectionchange', handler);
  }, []);

  return [ref, selection];
}

Use Cases

  • Text annotation tools
  • Inline commenting

Tags

Related Snippets

Similar patterns you can reuse in the same workflow.