Skip to content

fix: preserve shape across id changes for cross-container sort animations#1925

Open
clauderic wants to merge 1 commit intomainfrom
sortable-animation-improvements
Open

fix: preserve shape across id changes for cross-container sort animations#1925
clauderic wants to merge 1 commit intomainfrom
sortable-animation-improvements

Conversation

@clauderic
Copy link
Copy Markdown
Owner

Summary

  • Introduces a shapeStore cache that captures the droppable shape at drag start and keeps it updated after each animation frame
  • Modifies Sortable.animate() to accept an idChanged flag, using the cached shape when the sortable's identity has changed due to cross-container reparenting
  • Adds an effect that triggers animation when a cached shape exists and drag status changes, ensuring smooth transitions even after group/container changes

Problem

When a sortable item moves between containers (e.g., from list A to list B), its droppable identity changes and the previous droppable.shape reference is lost before the animation can compute the correct positional delta. This caused animations to either skip or produce incorrect visual transitions during cross-container sorting.

Test plan

  • Drag items between multiple sortable lists and verify smooth animation transitions
  • Verify single-list sorting animations are unaffected
  • Test with the MultipleLists story in Storybook

…ions

When a sortable item moves between containers, its droppable identity
changes and the previous shape reference is lost before the animation
can compute the correct delta. This introduces a shape cache (shapeStore)
that captures the droppable shape at drag start and updates it after
each animation frame, so the animate method always has a valid previous
shape to diff against — even after cross-container reparenting.

Co-authored-by: Cursor <cursoragent@cursor.com>
@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Feb 22, 2026

⚠️ No Changeset found

Latest commit: 56c20cf

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new bot commented Feb 22, 2026

Open in StackBlitz

@dnd-kit/abstract

npm i https://pkg.pr.new/clauderic/dnd-kit/@dnd-kit/abstract@1925

@dnd-kit/collision

npm i https://pkg.pr.new/clauderic/dnd-kit/@dnd-kit/collision@1925

@dnd-kit/dom

npm i https://pkg.pr.new/clauderic/dnd-kit/@dnd-kit/dom@1925

@dnd-kit/geometry

npm i https://pkg.pr.new/clauderic/dnd-kit/@dnd-kit/geometry@1925

@dnd-kit/helpers

npm i https://pkg.pr.new/clauderic/dnd-kit/@dnd-kit/helpers@1925

@dnd-kit/react

npm i https://pkg.pr.new/clauderic/dnd-kit/@dnd-kit/react@1925

@dnd-kit/solid

npm i https://pkg.pr.new/clauderic/dnd-kit/@dnd-kit/solid@1925

@dnd-kit/state

npm i https://pkg.pr.new/clauderic/dnd-kit/@dnd-kit/state@1925

@dnd-kit/svelte

npm i https://pkg.pr.new/clauderic/dnd-kit/@dnd-kit/svelte@1925

@dnd-kit/vue

npm i https://pkg.pr.new/clauderic/dnd-kit/@dnd-kit/vue@1925

commit: 56c20cf

clauderic

This comment was marked as duplicate.

Copy link
Copy Markdown
Owner Author

@clauderic clauderic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary

This PR fixes cross-container sort animations by introducing a shapeStore cache that preserves the droppable shape across identity changes (which happen when items move between containers). The cached shape is used when computing animation deltas after idChanged is true, ensuring smooth transitions even after the sortable's group/container changes.

Feedback

Blocking issues

  • Missing changeset: The changeset-bot already flagged this, but there's no .changeset/*.md file for the change to packages/dom/src/sortable/sortable.ts. A patch-level changeset for @dnd-kit/dom is needed before this can be released.

Suggestions

  • sortable.ts:190-196 — The new effect triggers animate(true) via queueMicrotask whenever status.dragging is true and a cached shape exists. Consider whether this could fire unnecessarily on each reactive update during a drag (e.g., every position change), potentially causing redundant animation calls. It might be worth guarding it more precisely (e.g., tracking when the id actually changed rather than just checking for a cached shape).
  • The shapeStore cache doesn't appear to have an explicit cleanup path at drag end. While the WeakStore prevents leaks when the manager is GC'd, stale shape entries could persist across multiple drag sessions within the same manager. A cleanup on drag idle/end might be worth considering.

Changeset

  • Status: missing — a .changeset/*.md with "@dnd-kit/dom": patch is required.

Overall

The approach is sound and addresses a real pain point with cross-container animations. The cache strategy is elegant. Just needs a changeset added before merge.


[claude-review]

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant