#3888·headlessui

@headlessui/vue Dialog gets stuck unscrollable on iOS after touching outside it (same bug as #3234, fixed for React in #3801 but not ported)

Author: MILLERMARRUCreated Aug 15, 2026Updated Aug 15, 2026

What package within Headless UI are you using?

@headlessui/vue

What version of that package are you using?

1.7.23 (latest)

What browser are you using?

Safari on iOS

Describe your issue

This looks like the same bug reported for @headlessui/react in #3234 and fixed there in #3801, but the fix never made it into @headlessui/vue.

In packages/@headlessui-vue/src/hooks/document-overflow/handle-ios-locking.ts the touchstart handler on doc decides on every touch whether it started inside an allowed (Dialog) container or not:

javascript
d.addEventListener(doc, 'touchstart', (e) => {
  if (e.target instanceof HTMLElement) {
    if (inAllowedContainer(e.target as HTMLElement)) {
      let rootContainer = e.target
      while (rootContainer.parentElement && inAllowedContainer(rootContainer.parentElement)) {
        rootContainer = rootContainer.parentElement!
      }
      d.style(rootContainer, 'overscrollBehavior', 'contain')
    } else {
      d.style(e.target, 'touchAction', 'none')
    }
  }
})

Once you touch outside the Dialog, touch-action: none gets applied to whatever element was touched and never resets. Because the listener stays on document, later touchstart events keep firing, but nothing clears the previously applied touchAction/overscrollBehavior styles before evaluating the new touch, so scrolling and pinch-zooming inside the Dialog stop working entirely until it's closed and reopened.

I compared this against the current @headlessui/react source for the same file and the fix in #3801 wraps the style side effects in a disposable group and disposes the previous group at the start of every touchstart, so the state gets reset and recomputed each time instead of accumulating. The Vue file I read still has the pre-fix version verbatim, no dispose/reset logic anywhere in that handler.

Reproduction

  1. Open a Dialog on iOS Safari.
  2. Scroll and pinch-zoom inside the Dialog, works fine.
  3. Tap or scroll once on the page outside the Dialog.
  4. Try to scroll or pinch-zoom inside the Dialog again, it no longer responds until the Dialog is closed and reopened.

Same repro as #3234, just against @headlessui/vue instead of @headlessui/react.

Expected behavior

Interacting with the Dialog should keep working normally on iOS even after a touch outside it happens, matching the fix already shipped for @headlessui/react in #3801.