Skip to content

Commit 20b3b65

Browse files
authored
Further fine tune scroll locking on iOS (#2891)
* further fine tune scroll locking on iOS * update CHANGELOG
1 parent 5976b9a commit 20b3b65

File tree

2 files changed

+19
-21
lines changed

2 files changed

+19
-21
lines changed

packages/@headlessui-react/CHANGELOG.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10-
- Nothing yet!
10+
### Fixed
11+
12+
- Further fine tune scroll locking on iOS ([#2891](https://github.com/tailwindlabs/headlessui/pull/2891))
1113

1214
## [2.0.0-alpha.2] - 2023-12-20
1315

packages/@headlessui-react/src/hooks/document-overflow/handle-ios-locking.ts

Lines changed: 16 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -95,30 +95,26 @@ export function handleIOSLocking(): ScrollLockStep<ContainerMetadata> {
9595
// Check if we are scrolling inside any of the allowed containers, if not let's cancel the event!
9696
if (e.target instanceof HTMLElement) {
9797
if (inAllowedContainer(e.target as HTMLElement)) {
98-
// We are in an allowed container, however on iOS the page can still scroll in
99-
// certain scenarios...
100-
let rootContainer = e.target
101-
while (
102-
rootContainer.parentElement &&
103-
inAllowedContainer(rootContainer.parentElement)
104-
) {
105-
rootContainer = rootContainer.parentElement!
106-
}
107-
108-
let scrollableParent = rootContainer
98+
// Even if we are in an allowed container, on iOS the main page can still scroll, we
99+
// have to make sure that we `event.preventDefault()` this event to prevent that.
100+
//
101+
// However, if we happen to scroll on an element that is overflowing, or any of its
102+
// parents are overflowing, then we should not call `event.preventDefault()` because
103+
// otherwise we are preventing the user from scrolling inside that container which
104+
// is not what we want.
105+
let scrollableParent = e.target
109106
while (
110107
scrollableParent.parentElement &&
111-
// Assumption that we are always used in a Headless UI Portal. Once we reach the
112-
// portal, its over.
108+
// Assumption: We are always used in a Headless UI Portal. Once we reach the
109+
// portal itself, we can stop crawling up the tree.
113110
scrollableParent.dataset.headlessuiPortal !== ''
114111
) {
115-
// Verify that we are in a scrollable container (which may or may not overflow yet)
116-
let css = window.getComputedStyle(scrollableParent)
117-
if (/(auto|scroll)/.test(css.overflow + css.overflowY + css.overflowX)) {
118-
break
119-
}
120-
121-
// Check if the scrollable container is already overflowing
112+
// Check if the scrollable container is overflowing or not.
113+
//
114+
// NOTE: we could check the `overflow`, `overflow-y` and `overflow-x` properties
115+
// but when there is no overflow happening then the `overscrollBehavior` doesn't
116+
// seem to work and the main page will still scroll. So instead we check if the
117+
// scrollable container is overflowing or not and use that heuristic instead.
122118
if (
123119
scrollableParent.scrollHeight > scrollableParent.clientHeight ||
124120
scrollableParent.scrollWidth > scrollableParent.clientWidth

0 commit comments

Comments
 (0)