Skip to content

Replace mousedown/touchstart/touchend with pointerdown/pointerup #878

Closed

Description

@delijah

Is your feature request related to a problem? Please describe.

With the more modern events pointerdown/pointerup you can make use of pointer capture, which makes the whole drag UX better. For example you have better control over the cursor (it will not blink).

Describe the solution you'd like

Replace mousedown/touchstart/touchend with pointerdown/pointerup. But this will also not support as many browsers as the current solution. An alternative would be, to add those events on top. Just call this hook on top for example:

Describe alternatives you've considered

const useResizerEffects = (ref: RefObject<HTMLDivElement>) => {
    useEffect(() => {
        const element = ref.current;

        if (!element) {
            return;
        }

        const pointerIds = new Set<number>();

        const handlePointerDown = (e: PointerEvent) => {
            element.setPointerCapture(e.pointerId);

            pointerIds.add(e.pointerId);
        };

        const handlePointerUp = (e: PointerEvent) => {
            if (element.hasPointerCapture(e.pointerId)) {
                element.releasePointerCapture(e.pointerId);
            }

            pointerIds.delete(e.pointerId);
        };

        element.addEventListener('pointerdown', handlePointerDown);
        element.addEventListener('pointerup', handlePointerUp);
        element.addEventListener('pointercancel', handlePointerUp);

        return () => {
            element.removeEventListener('pointerdown', handlePointerDown);
            element.removeEventListener('pointerup', handlePointerUp);
            element.removeEventListener('pointercancel', handlePointerUp);

            pointerIds.forEach((pointerId) => {
                if (element.hasPointerCapture(pointerId)) {
                    element.releasePointerCapture(pointerId);
                }
            });
        };
    }, [ref]);
};

Activity

  1. tomkp commented on Feb 18, 2026

    @tomkp
    Owner

    Thanks for the feature request! I've reviewed this and agree it's a worthwhile improvement.

    Analysis

    Current State

    The useResizer hook currently handles mouse and touch events separately with:

    • handleMouseDown / handleMouseUp / handleMouseMove for mouse
    • handleTouchStart / handleTouchEnd / handleTouchMove for touch
    • Global document listeners attached during drag

    Pros of Pointer Events

    1. Better cursor control - setPointerCapture() prevents cursor blinking during drag since the element captures all pointer events
    2. Unified event handling - Pointer Events handle mouse, touch, and pen input with a single set of events
    3. Cleaner code - Reduces duplication between mouse and touch handlers
    4. More reliable drag behavior - Captured pointer events continue even if pointer leaves the element
    5. Modern standard - Pointer Events are the recommended approach for handling pointing device input

    Cons / Considerations

    1. Browser support - Pointer Events require IE11+ / all modern browsers since ~2017. However, since we already target React 17/18/19 and Node 20+, this isn't a concern
    2. Breaking change for custom dividers - Custom divider components will need to handle onPointerDown instead of onMouseDown/onTouchStart

    Decision

    Going with full replacement rather than the additive approach because:

    • The project already targets modern React versions
    • Pointer Events have excellent browser support (5+ years)
    • It simplifies the codebase significantly
    • The existing mouse/touch event split adds unnecessary complexity
  2. added a commit that references this issue on Feb 18, 2026
    a67f4bc
  3. tomkp commented on Feb 18, 2026

    @tomkp
    Owner

    @delijah This has been implemented and released in v3.1.0 🎉

    The library now uses the Pointer Events API with setPointerCapture() for better drag UX - no more cursor blinking!

    What's included:

    • Unified pointer events (handles mouse, touch, and pen)
    • Pointer capture for reliable drag behavior
    • Pointer ID filtering for multi-touch support

    Backwards compatible: If you have custom dividers using onMouseDown/onTouchStart/onTouchEnd, they'll continue to work. Those props now delegate to onPointerDown internally (marked as deprecated).

    Thanks for the suggestion - let me know if it works for you!

  4. added a commit that references this issue on Feb 18, 2026
    c8452c8
  5. delijah commented on Feb 19, 2026

    @delijah
    Author

    Wow, amazing. Thank you a lot ! 🙏

  6. delijah commented on Feb 19, 2026

    @delijah
    Author

    @tomkp by the way: For source you could also use event.pointerType if you need more accurate info what the pointer action initiated.

  7. tomkp commented on Feb 19, 2026

    @tomkp
    Owner

    @delijah Good suggestion! Implemented in #880 - pointerType is now available in the ResizeEvent:

    onResizeStart={(event) => {
      console.log(event.pointerType); // 'mouse', 'touch', or 'pen'
    }}

    Will be in the next release.

  8. tomkp commented on Feb 19, 2026

    @tomkp
    Owner

    @delijah v3.2.0 has been published to npm with the pointerType feature. 🎉

    Thanks Tom

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions