bug(dialog): body scroll-lock and pointer-events not restored after conditional Dialog unmount in React StrictMode
## 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 条评论