ITADN

bug(dialog): body scroll-lock and pointer-events not restored after conditional Dialog unmount in React StrictMode

#3842Closedbertho-zero 创建于 2026-03-31
B
bertho-zerocommented
## Bug When a Chakra UI v3 / Ark UI Dialog is conditionally rendered (`{show && <Dialog.Root open={true}>}`) and the wrapper component is unmounted, `pointer-events: none`, `overflow: hidden`, and `padding-right` remain stuck on `document.body`, making the page completely unresponsive. This only happens with **React StrictMode** enabled. It does **not** reproduce with `@zag-js/dialog` + `@zag-js/react` directly — only through the Ark UI / Chakra UI wrapper. ## Reproduction **StackBlitz:** https://stackblitz.com/edit/szdx61wd?file=src%2FApp.tsx Steps: 1. Click **"Show Dialog component"** (mounts the component) 2. The dialog opens automatically (`open={true}`) 3. Close the dialog (Close button, Escape, or backdrop click) 4. Click **"Hide component (unmount)"** (unmounts the component) 5. Observe the body style monitor → `pointer-events: none`, `overflow: hidden` remain stuck **Note:** The same pattern with `@zag-js/dialog` + `@zag-js/react` directly (no Ark/Chakra wrapper) does **not** exhibit this bug. ## Expected `document.body` styles should be fully restored after the Dialog component unmounts. ## Actual After unmount, `document.body` retains: - `pointer-events: none` - `overflow: hidden` - `padding-right: Xpx` - `data-scroll-lock` attribute - `data-inert` attribute The page becomes completely frozen — no clicks, no scroll. ## Workaround Use controlled `open` prop without conditional rendering: ```tsx // Instead of: {show && <Dialog.Root open={true}>...</Dialog.Root>} // Use: <Dialog.Root open={show}>...</Dialog.Root> ``` This avoids unmounting the Dialog.Root, letting the dialog machine manage its lifecycle and cleanup properly. ## Environment - `@chakra-ui/react`: 3.34.0 - `@ark-ui/react`: 5.35.0 - `@zag-js/react`: 1.38.2 - `@zag-js/dismissable`: 1.38.2 - `react`: 18.3.1 (StrictMode enabled) - Vite 6.x
关闭于 2026-03-31 1 条评论