Fix AnimatePresence popLayout RTL positioning#3653
Conversation
PopChild used the physical `left` CSS property for positioning exiting elements, which breaks in RTL layouts where fit-content containers shrink from the left. Now detects text direction and uses the appropriate physical property (`right` in RTL) to anchor to the stable edge. Fixes #2952 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Greptile SummaryThis PR fixes a visual positioning bug in Key changes:
Note: The fix correctly resolves the default Confidence Score: 4/5
Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[getSnapshotBeforeUpdate\nElement going from present → absent] --> B[Read computedStyle.direction\nStore in size.direction]
B --> C[useInsertionEffect fires\nElement is no longer present]
C --> D{isRTL?\ndirection === 'rtl'}
D -- No / LTR --> E{anchorX === 'left'?}
D -- Yes / RTL --> F{anchorX === 'left'?}
E -- Yes --> G["left: left_px\n(stable left edge in LTR)"]
E -- No --> H["right: right_px\n(right-anchored in LTR)"]
F -- Yes / Default --> I["right: right_px\n✅ Stable right edge in RTL fit-content"]
F -- No / anchorX='right' --> J["left: left_px\n⚠️ Unstable left edge in RTL fit-content"]
G --> K[Inject CSS rule via style sheet]
H --> K
I --> K
J --> K
K --> L[Exiting element held in place during animation]
Last reviewed commit: 3212dd9 |
| const x = anchorX === "left" | ||
| ? (isRTL ? `right: ${right}` : `left: ${left}`) | ||
| : (isRTL ? `left: ${left}` : `right: ${right}`) |
There was a problem hiding this comment.
RTL positioning for
anchorX="right" may still shift
When anchorX is explicitly set to "right" in an RTL fit-content container, the fix now uses left: ${left} (physical left) which is the unstable edge in RTL. In a right-to-left fit-content container, the right edge remains fixed when the container shrinks — so both anchorX="left" and anchorX="right" would need to use right: ${right} to stay visually anchored.
The new behavior:
// anchorX === "right", isRTL === true
`left: ${left}` // left edge is unstable in RTL fit-content → element shiftsThe pre-fix behavior for anchorX="right" in RTL happened to be correct:
// anchorX !== "left" → `right: ${right}` (stable edge in RTL fit-content) ✓This PR only fixes the default anchorX="left" case. If anchorX="right" is used in RTL, the same positional shifting bug can still occur. Consider whether the swap should always use the stable edge (right) in RTL regardless of anchorX, or document that anchorX="right" is unsupported in RTL contexts.
Summary
AnimatePresencewithmode="popLayout"used the physicalleftCSS property to position exiting elements. In RTL layouts withfit-contentcontainers, the container shrinks from the left edge (right edge stays fixed), causing the absolutely positioned exiting element to visually shift.PopChild.tsxhardcodedleft: ${offsetLeft}pxregardless of text direction. In RTL, when the container shrinks, its left edge moves right, dragging theleft-anchored element with it.directionduring measurement and use the appropriate physical CSS property —rightin RTL (anchoring to the stable edge) orleftin LTR (default behavior unchanged).Fixes #2952
Test plan
animate-presence-pop-rtl) verifies exiting element maintains its viewport position in an RTL flex container withfit-contentanimate-presence-popCypress tests still pass🤖 Generated with Claude Code