Skip to content

ScrollArea: fast thumb drag can leave webkitUserSelect and pointer capture stuck #1900

@preening

Description

@preening

Description

When dragging the ScrollArea thumb quickly, pointerup sometimes fails to fire cleanly, leaving the page in a broken state:

  1. Text becomes unselectabledocument.body.style.webkitUserSelect stays "none"
  2. Scrollbar sticks to mouse — pointer capture is never released, so the thumb follows the cursor without clicking

Reproduction

  1. Render a ScrollArea with enough content to scroll
  2. Grab the scrollbar thumb and drag it very quickly
  3. Release the mouse button
  4. Try to select text anywhere on the page — cursor won't change and text is unselectable
  5. Move mouse into scrollbar region — thumb teleports to mouse and sticks

Root Cause

In scroll-area.svelte.ts lines 770-795:

onpointerdown(e: BitsPointerEvent) {
    target.setPointerCapture(e.pointerId);
    this.root.domContext.getDocument().body.style.webkitUserSelect = "none";
    // ...
}

onpointerup(e: BitsPointerEvent) {
    target.releasePointerCapture(e.pointerId);
    this.root.domContext.getDocument().body.style.webkitUserSelect = this.prevWebkitUserSelect;
    // ...
}

If pointerup is missed (fast drag, system interrupt, etc.), there's no fallback to restore state.

Suggested Fix

  • Add a timeout fallback to reset state if no pointerup within ~100ms of last pointermove
  • Or use the existing TextSelectionLayer utility pattern for scoped user-select management
  • Or add a pointercancel handler as a safety net

Environment

  • bits-ui: latest
  • Browser: Chrome/Safari (both affected)
  • OS: macOS

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions