You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Extract and re-use vertical scroll re-order for horizontal scroll
Add auto-horizontal scroll when reordering table columns
Fix small bug in virtualisation by keeping the dragged item rendered to avoid unmount after it left viewport
demo-auto-scroll.mov
Notes
The auto-scroll logic moved out of ReorderHandle into startDragAutoScroll(axis, table, preferredScroller, onScroll), so rows (y) and columns (x) share the same code.
Differences from the previous row-only implementation:
Continuous scroll: a requestAnimationFrame loop scrolls while the pointer stays near an edge
Before, scrolling only happened on pointermove (throttled to 100px every 200ms), so holding the pointer still at the edge did nothing
Speed depends on the distance to the edge: from 1px to 16px per frame inside an edge area of min(100px, 30% of the visible size)
A pointer outside the scroller scrolls at max speed
The 30% cap keeps the middle of small scrollers free of auto scroll
Scroller detection:
Rows (y) use TableProps.scrollerRef when set
Columns (x) and rows without scrollerRef use the nearest ancestor that actually scrolls along the axis, falling back to the window
scrollerRef is skipped for columns because the vertical virtualization container may not scroll horizontally
Stops at the table edge: no scrolling once the table's start/end is already visible
behavior: 'instant': smooth scrolling would restart its animation on every frame
onScroll callback: called with the last pointer position on every frame, so the handle and insertion indicator stay under a stationary pointer after any scroll, including the user's wheel scroll
Virtualization fix
While dragging a row, the button follows the pointer but the original <tr> stays in place.
When auto scroll moves that row past the retention margin, virtualization collapses it into a spacer and ReorderHandle unmounts, which ends the drag in the middle.
ReorderHandle now sets the data-reordering attribute on the dragged row on pointerdown and removes it on cleanup. onIntersectionChange() stays the single place that decides whether to collapse: DefaultItemRenderer returns undefined (keep rendered) while the attribute is set.
Custom renderers that call useItemVirtualization() should do the same check.
After release, a cancelled drag can leave the row rendered off-screen until the next intersection change, since IntersectionObserver doesn't fire again.
That's at most one extra row, so it's accepted.
A successful drop changes the indexes, which re-observes the row and collapses it.
Adds horizontal auto-scroll for table column reordering and shares the scrolling logic with row reordering. Also retains dragged rows during virtualization to prevent the drag handle from unmounting offscreen.
Changes:
Introduces continuous, edge-sensitive auto-scroll for both axes.
Updates drag visuals during scrolling and retains dragged rows until cleanup.
Adds horizontal-scroll tests and stories for page and container scrolling.
File
Description
src/table/table.test.tsx
Tests horizontal auto-scroll, drop cleanup, and table-edge stopping.
The reason will be displayed to describe this comment to others. Learn more.
🟡 Changes recommended
Auto-scroll ignores ancestor clipping bounds, and drag cancellation can invoke a stale callback that restores spacers for removed rows after data shrinks.
Constrain auto-scroll edges to ancestor clipping bounds
src/table/internal/drag-auto-scroll.ts:42
This only clips the scroller's bounds to the window, not to overflow-clipping ancestors. For example, with an 800px-wide inner scroller clipped to 400px by an overflow: hidden parent, dragging at x=390 produces no auto-scroll: the helper still treats x=800 as the right edge, which the user cannot reach within the visible container. Please intersect the range with ancestor clipping bounds before calculating the edge area.
The reason will be displayed to describe this comment to others. Learn more.
Thx for further improving the component. Please take a look on comments I left in drag-auto-scroll.ts and the API ideas in virtualization.tsx (above). Thank you.
The reason will be displayed to describe this comment to others. Learn more.
🟡 Changes recommended
Column drags can target the wrong horizontal scroll container, and suppressed visibility notifications can leave offscreen rows mounted after drag cancellation.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
In this PR:
demo-auto-scroll.mov
Notes
The auto-scroll logic moved out of
ReorderHandleintostartDragAutoScroll(axis, table, preferredScroller, onScroll), so rows (y) and columns (x) share the same code.Differences from the previous row-only implementation:
requestAnimationFrameloop scrolls while the pointer stays near an edgepointermove(throttled to 100px every 200ms), so holding the pointer still at the edge did nothingmin(100px, 30% of the visible size)y) useTableProps.scrollerRefwhen setx) and rows withoutscrollerRefuse the nearest ancestor that actually scrolls along the axis, falling back to the windowscrollerRefis skipped for columns because the vertical virtualization container may not scroll horizontallybehavior: 'instant': smooth scrolling would restart its animation on every frameonScrollcallback: called with the last pointer position on every frame, so the handle and insertion indicator stay under a stationary pointer after any scroll, including the user's wheel scrollVirtualization fix
While dragging a row, the button follows the pointer but the original
<tr>stays in place.When auto scroll moves that row past the retention margin, virtualization collapses it into a spacer and
ReorderHandleunmounts, which ends the drag in the middle.ReorderHandlenow sets thedata-reorderingattribute on the dragged row onpointerdownand removes it on cleanup.onIntersectionChange()stays the single place that decides whether to collapse:DefaultItemRendererreturnsundefined(keep rendered) while the attribute is set.Custom renderers that call
useItemVirtualization()should do the same check.After release, a cancelled drag can leave the row rendered off-screen until the next intersection change, since
IntersectionObserverdoesn't fire again.That's at most one extra row, so it's accepted.
A successful drop changes the indexes, which re-observes the row and collapses it.