Modal disableScrollLock behavior with nested Modals
0 reputation · 03 Oct 2023, 10:39 UTC
0 reputation · 03 Oct 2023, 10:39 UTC
Configuring MUI Modal scroll lock for nested dialogs requires a clear rule for how disableScrollLock propagates between parent and child instances.
The disableScrollLock prop disables the automatic body scroll lock that Modal applies when open. Each Modal instance manages scroll locking independently, and documentation does not guarantee propagation of scroll lock behavior across nested Modals. This leaves uncertainty about the desired permission boundary for background scrolling when an outer Modal disables locking while an inner Modal uses the default.
The goal is a predictable scroll lock policy for a stack of Modals with mixed disableScrollLock settings, without manual overflow management.
Does disableScrollLock on an outer Modal influence the scroll lock applied by a nested child Modal? Is there a documented way to enforce a consistent scroll lock state across a Modal stack? What is the expected document.body.style.overflow behavior when parent and child Modals have different disableScrollLock values?
31775 reputation · 03 Oct 2023, 19:44 UTC
No, disableScrollLock on an outer Modal does not influence a nested child Modal. Each Modal instance manages scroll locking independently via its own useEffect. There is no documented API in MUI v5/v6 to coordinate scroll lock state across a Modal stack.
disableScrollLock={true} and a child with the default false will still result in the child locking document.body.style.overflow to "hidden" when it mounts.body.style.overflow. This makes the final state non-deterministic when conditional rendering or portal order changes.disableScrollLock={true}, the inner's cleanup on unmount may restore scroll while the outer remains open.disableScrollLock values create race conditions on the single body style.Lift scroll lock control to a common ancestor and manage it with a reference counter:
function useModalStackLock() {
const count = React.useRef(0);
const lock = React.useCallback(() => {
if (++count.current === 1) document.body.style.overflow = 'hidden';
}, []);
const unlock = React.useCallback(() => {
if (--count.current === 0) document.body.style.overflow = '';
}, []);
return { lock, unlock };
}
// In a wrapper component that renders the Modal stack:
const { lock, unlock } = useModalStackLock();
<Modal open={outerOpen} disableScrollLock onOpen={lock} onClose={unlock}>
<Modal open={innerOpen} disableScrollLock>...</Modal>
</Modal>Pass disableScrollLock={true} to every Modal in the stack and let the hook drive body.overflow based on the number of currently open Modals.
disableScrollLock combinations (parent/child true/false).document.body.style.overflow in DevTools after each mount/unmount.console.log in a custom useEffect inside each Modal to track when lock is applied/removed.package.json; the hooks-based implementation differs from v4.What MUI version are you using? The scroll lock implementation changed between v4 (class-based) and v5+ (hooks-based), and the exact race-condition behavior can vary by minor version.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.