fix(ui): resolve SSR hydration mismatch in DraggableSortable (aria-describedby)#16171
Open
devinoldenburg wants to merge 1 commit intopayloadcms:mainfrom
Open
Conversation
useId() generates different values between server and client when DraggableSortable is mounted inside a subtree that was not part of the initial SSR output (e.g. a hidden column-picker portal in list views). @dnd-kit derives aria-describedby on every sortable item from the DndContext id, so any server/client id mismatch triggers a React hydration warning for every draggable pill. Fix: initialise both ids through useState so they are only ever produced on the client side and remain stable across re-renders. Closes #<issue>
Member
|
Can you verify you're getting SSR issues using one of the supported Next.js versions? This used to be a React bug that was present in older Next.js versions. If this is addressed by bumping Next.js, we won't need this change |
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Problem
When
DraggableSortableis mounted inside a subtree that was not part of the initial SSR output (e.g. the hidden column-picker panel in collection list views),useId()produces different values between the server render and the client hydration pass.@dnd-kitderivesaria-describedbyon every sortable item from theDndContextid. Because the id differs, React emits a hydration mismatch warning for every draggable pill in the selector:This affects all collection list views that use the column picker (Videos, Offers, Reviews, etc.).
Root cause
useId()is deterministic only when the component tree rendered on the server matches the tree hydrated on the client. When a component is conditionally mounted (hiddendiv, portal, lazy panel), the hook's counter is incremented differently on each side, producing mismatched ids.Fix
Initialise both
dndContextIDandsortableContextIDthroughuseStateinstead of using theuseId()value directly.useStateinitialises only on the client, so the id is never included in SSR output and there is nothing to mismatch.The values remain stable across re-renders (empty deps in
useState), so drag-and-drop behaviour is unaffected.References