-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Description
7. Environment details
Arc: Version 1.107.0 (66519)
Chromium Engine Version 139.0.7258.67
macOS 15.5
framer-motion: 11.18.2 (I have since upgraded to current motion@12.23.12 but the affected code seems to be the same between these versions)
2. Describe the bug
In our software, there are super rare cases where this error occurs: TypeError: Cannot read properties of null (reading 'scrollLeft'). It's this line in DocumentProjectionNode, document.body.scrollLeft to be exact:
| x: document.documentElement.scrollLeft || document.body.scrollLeft, |
The error occurs during rapid scrolling/zooming of a large scrollable area with loads of DOM elements (it's something like a Gantt-Chart).
3. IMPORTANT: Provide a CodeSandbox reproduction of the bug
I get it that you won't accept bug reports without reproduction. Since it only occurs very rarely, I unfortunately did not manage to reliably reproduce this.
I'm not exactly sure how document.body can even be null in the first place. The error occurs well after the application has loaded. I'm certain that it cannot be some code that runs before there is a body.
This is what Claude Sonnet 4 has to say, so take it with a grain of salt. But it seems vaguely plausible:
DOM Manipulation Edge Cases
With lots of DOM operations (which you mentioned), these scenarios become possible:
- The element gets temporarily removed via document.body.remove() or similar
- Document fragments or aggressive DOM manipulation temporarily detaches the body
- Race conditions where one part of code removes/replaces the body while another tries to access it
Browser-Specific Edge Cases
During rapid scrolling/zooming operations:
- Some browsers might temporarily detach elements during heavy reflows/repaints
- Memory pressure from lots of DOM elements could cause temporary cleanup
- Browser optimization during intensive operations might cause brief DOM inconsistencies
It must be triggered by one of these since those are the only occurences of motion in this code path. But I'm not sure which exactly (left out some attributes like classNames and stuff that most likely does not matter).
<motion.button
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0, transition: { delay: 0 } }}
transition={{ delay: 1 }}
type="button"
>
{ /* … */ }
</motion.button><AnimatePresence initial={false}>
{deferredOpen && (
<motion.div
initial={{ height: 0, overflow: 'clip' }}
exit={{ height: 0, overflow: 'clip' }}
animate={{ height: 'auto', overflow: 'visible' }}
transition={{ duration: 0.2 }}
onAnimationStart={() => {
itemRef.current?.setAttribute('style', 'overflow: clip');
}}
onAnimationComplete={() => {
if (open) {
itemRef.current?.removeAttribute('style');
}
}}
>
{ /* … */ }
</motion.div>
)}
</AnimatePresence> <motion.div
animate={{
backgroundColor: highlighted
? // notice-4
'#FFE3016B'
: '#FFFFFF00',
transition: {
delay: highlighted ? 0.6 : 0,
duration: 0.3,
ease: 'easeInOut',
},
}}
initial={false}
onAnimationComplete={() => {
if (highlighted) {
highlightContext.setHighlightedEventId(null);
}
}}
/>4. Steps to reproduce
- In our application, scroll a lot
5. Expected behavior
This error should not occur.
This would be a fix of course. Not sure if there's a better solution. Possibly wrapping it in requestAnimationFrame?
import { addDomEvent } from "../../events/add-dom-event"
import { createProjectionNode } from "./create-projection-node"
export const DocumentProjectionNode = createProjectionNode<Window>({
attachResizeListener: (
ref: Window | Element,
notify: VoidFunction,
): VoidFunction => addDomEvent(ref, 'resize', notify),
measureScroll: () => ({
x: (document.documentElement.scrollLeft || document.body?.scrollLeft) ?? 0,
y: (document.documentElement.scrollTop || document.body?.scrollTop) ?? 0,
}),
checkIsScrollRoot: () => true,
});6. Video or screenshots
