`useDismiss` still closes floating elements when clicking content scrollbars (incomplete fix from #1820)

Author: jaredpdesignsCreated Oct 16, 2025Updated Jul 13, 2026
Labelsbughas workaround

Bug Description

PR #1820 fixed scrollbar detection for page-level scrollbars, but content scrollbars within floating elements still incorrectly trigger outsidePress dismissal. This creates inconsistent behavior where some scrollbars work (page-level) while others don't (content-level).

Reproduction

  1. Create floating element with scrollable content (overflow: auto, content exceeds container height)
  2. Click floating element's scrollbar to scroll
  3. Bug: Element dismisses instead of scrolling

Root Cause

Current fix only handles document scrollbars, not scrollbars within floating element content. Need to detect:

  • Traditional scrollbars (take layout space)
  • Overlay scrollbars (macOS style, no layout space)

Proposed Solution

Scrollbar Detection Function

typescript
function isScrollbarClick(element: HTMLElement, clientX: number, clientY: number): boolean {
  const rect = element.getBoundingClientRect();
  const scrollbarWidth = element.offsetWidth - element.clientWidth;
  const scrollbarHeight = element.offsetHeight - element.clientHeight;
  
  // Traditional scrollbar detection
  const isVerticalScrollbar = scrollbarWidth > 0 && clientX >= rect.right - scrollbarWidth;
  const isHorizontalScrollbar = scrollbarHeight > 0 && clientY >= rect.bottom - scrollbarHeight;
  
  // Overlay scrollbar detection (15px threshold from edges)
  const hasVerticalScroll = element.scrollHeight > element.clientHeight;
  const hasHorizontalScroll = element.scrollWidth > element.clientWidth;
  const isOverlayVertical = hasVerticalScroll && scrollbarWidth === 0 && (rect.right - clientX) <= 15;
  const isOverlayHorizontal = hasHorizontalScroll && scrollbarHeight === 0 && (rect.bottom - clientY) <= 15;
  
  return isVerticalScrollbar || isHorizontalScrollbar || isOverlayVertical || isOverlayHorizontal;
}

Integration with useDismiss

typescript
const dismiss = useDismiss(context, {
  outsidePress: (event) => {
    const target = event.target as HTMLElement;
    
    // Find scrollable floating element containing the click target
    const floatingElement = target.closest('[data-floating-ui-element]'); // or similar selector
    
    if (floatingElement && isScrollbarClick(floatingElement, event.clientX, event.clientY)) {
      return false; // Don't dismiss on scrollbar clicks
    }
    
    return true; // Continue normal outside press logic
  }
});

Implementation Notes

  • Non-breaking: Enhances existing behavior without API changes
  • Cross-platform: Handles Windows traditional + macOS overlay scrollbars
  • Configurable: Could add options for overlay scrollbar threshold

This would complete the scrollbar fix started in #1820 and provide consistent behavior across all scrollbar types.

Related

  • #1779 - Original scrollbar issue
  • #1820 - Partial fix for page scrollbars