clauderic / dnd-kit

The modern, lightweight, performant, accessible and extensible drag & drop toolkit for React.
http://dndkit.com
MIT License
12.96k stars 643 forks source link

Scroll position jumps after auto scrolling during drag and drop #825

Open shawnshuang opened 2 years ago

shawnshuang commented 2 years ago

Description

I’m running into an issue where the scroll position jumps after I auto scroll while dragging and dropping an element. I’m also not sure if this issue is coming from how I’m using dnd-kit or react-virtuoso (the virtual list library that I’m using), so I’m creating GitHub issues in both repos.

The issue seems to occur sporadically. It occurs only if there’s auto scrolling during drag and drop. And it occurs only if the auto scrolling is done downwards.

Do you think this issue is coming from how I’m using dnd-kit? If so, would you have any suggestions on how I can get rid of the scroll jump?

CodeSandbox

Here is a simplified CodeSandbox that reproduces the issue. (Excuse the comments; they’re for explaining parts of dnd-kit to the author of react-virtuoso.)

Video

Below is a video that illustrates the issue. You can see that the elements are dropped in the correct order in the list, but the scroll position shifts when the element is dropped, which is disorientating.

https://user-images.githubusercontent.com/7409323/178077335-fd97f79d-9671-46aa-9374-23c9f341f092.mov

sjc5 commented 1 year ago

Also seeing this issue, exactly as described.

chkp-michaelo commented 1 year ago

Confirming this happens with react-window, simply by having the rows draggable (no droppables, no sort manager). I noticed that the jumps always land on the initial scroll position when the drag has started, as if there's some 'reset'.

LeviRemi commented 1 year ago

Also confirming I see this behavior with react-window.

@MichaelOstrovsky or @shawnshuang - Any luck finding a workaround?

clauderic commented 1 year ago

As a temporary workaround, can you try setting the layoutShiftCompensation option of the autoScroll prop to false?

Something like:

<DndContext autoScroll={{layoutShiftCompensation: false}}>
LeviRemi commented 1 year ago

Major thanks, @clauderic! That completely eliminated the jumping on drag-and-scroll. I was not aware this was even an option. Are all of the autoScroll customizations documented somewhere?

LeviRemi commented 1 year ago

@clauderic Before I forget.. another question for autoScroll options:

Is there any way to completely eliminate horizontal auto-scroll?

clauderic commented 1 year ago

Is there any way to completely eliminate horizontal auto-scroll?

<DndContext autoScroll={{ threshold: { x: 0, y: 0.2 } }} >

Are all of the autoScroll customizations documented somewhere

The autoScroll config is a bit experimental so is only documented via the type definitions: https://github.com/clauderic/dnd-kit/blob/master/packages/core/src/hooks/utilities/useAutoScroller.ts#L15-L32

shawnshuang commented 1 year ago

@clauderic Thanks for taking the time to respond! Unfortunately, I'm still seeing the issue. I updated the code in my sandbox with the layoutShiftCompensation option if you'd like to see for yourself. I'm not sure if it would have done anything, but I also made sure to update @dnd-kit/core in the sandbox from 6.0.2 to 6.0.8 and @dnd-kit/sortable from 7.0.0 to 7.0.2.

I'm not sure if the issue that I'm seeing has to do with the virtualization library that I'm using, react-virtuoso. It seems the option resolved the issue for @LeviRemi, who was using react-window.

@MichaelOstrovsky I see that you're also using react-window; I would love to know if the layoutShiftCompensation option ends up resolving the issue for you!

gudlyf commented 1 year ago

I was seeing something similar on horizontal autoScroll and when I set acceleration: 1 it helped a ton.

<DndContext autoScroll={{ acceleration: 1 }}>

inokawa commented 1 year ago

https://github.com/inokawa/virtua may help because it suports similar usecases to react-virtuoso and it works well with dnd-kit.

https://inokawa.github.io/virtua/?path=/story/advanced-with-dnd-kit--default https://github.com/inokawa/virtua/blob/main/stories/react/advanced/With%20dnd-kit.stories.tsx

moxxuk commented 10 months ago

Is there another solution to this? I'm using https://github.com/TanStack/virtual, layoutShiftCompensation workaround did not work for me.

My hacky solution: I have resorted to patching the package, adding a new shouldScrollIntoView boolean prop (default: true) to DragOverlay, passing that prop to useDropAnimation, and only running the scrollIntoViewIfNeeded function if the boolean is true. When I don't want the scrolling to happen, I set the shouldScrollIntoView prop of DragOverlay to false.

There must be a better way...

subratre commented 8 months ago

Hi @clauderic, I've implemented react-dnd-kit, and it's working fine for both vertical and horizontal auto-scrolling. However, when I have multiple columns (e.g., 4 columns per row, then the next 4 in the second row) and one column has more than 100 items, sometimes when dragging an item, the auto-scrolling gets stuck for a few milliseconds, causing lagging and not flexing properly. Could you please share a solution for this?"

niranjan821 commented 7 months ago

I'm also facing the same issue. setting layoutShiftCompensation to false is not helping. I am not using react-virtuoso.

odin0v commented 6 months ago

I was seeing something similar on horizontal autoScroll and when I set acceleration: 1 it helped a ton.

<DndContext autoScroll={{ acceleration: 1 }}>

My problem is similar, when doing validations inside my "Droppable" component I used overflow-y-scroll and it generated the same error on my scroll x, I used a "useEffect" with the isOver variable of the useDroppable so that when the element lands in the container, overflow-y-scroll will be hidden

 useEffect(() => {
        isOver
            ? setClassNameContent("")
            : setClassNameContent("overflow-y-scroll");
    }, [isOver]);
sarten8 commented 6 months ago

@shawnshuang, @clauderic

In my case it works with: autoScroll={{ layoutShiftCompensation: false, enable: false }}

Lexachoc commented 3 weeks ago

Also face the same issue.

Using

<DndContext autoScroll={{layoutShiftCompensation: false, threshold: {x: 0, y: 0}}}

works for me

FranzAbsalon commented 2 weeks ago

I have the problem that when I drag and drop, there is the random spot of the scroll, I am using this useEffect method for horizontally scrolling. When I remove overflowX, the bug is fixed but the design if not that good.

useEffect(() => { const el = bodyRef.current; if (el) { const onWheel = (e) => { if (e.deltaY == 0) return; e.preventDefault(); el.scrollTo({ left: el.scrollLeft + e.deltaY, }); }; el.addEventListener("wheel", onWheel); return () => el.removeEventListener("wheel", onWheel); } }, []);

Here's the sample video of the bug: 
https://www.loom.com/share/4f61bfad84b74df891ef3bf917f46e88?sid=3d006e57-0a91-4bdc-b81d-6b7581e7d244