@@ -233,16 +233,20 @@ const Dropdown = ({
233
233
234
234
// Position normal overflow dropdowns with fixed positioning relative to viewport
235
235
if ( expandToViewport && ! interior ) {
236
- target . style . position = 'absolute' ;
236
+ const isIOSVirtualKeyboardPresent =
237
+ window . visualViewport ?. height && window . visualViewport . height < window . innerHeight ;
238
+ target . style . position = isIOSVirtualKeyboardPresent ? 'absolute' : 'fixed' ;
239
+ const verticalScrollOffset = isIOSVirtualKeyboardPresent ? document . documentElement . scrollTop : 0 ;
240
+ const horizontalScrollOffset = isIOSVirtualKeyboardPresent ? document . documentElement . scrollLeft : 0 ;
237
241
if ( position . dropBlockStart ) {
238
- target . style . insetBlockEnd = `calc(100% - ${ document . documentElement . scrollTop + triggerBox . top } px)` ;
242
+ target . style . insetBlockEnd = `calc(100% - ${ verticalScrollOffset + triggerBox . top } px)` ;
239
243
} else {
240
- target . style . insetBlockStart = `${ document . documentElement . scrollTop + triggerBox . bottom } px` ;
244
+ target . style . insetBlockStart = `${ verticalScrollOffset + triggerBox . bottom } px` ;
241
245
}
242
246
if ( position . dropInlineStart ) {
243
- target . style . insetInlineStart = `calc(${ triggerBox . right } px - ${ position . inlineSize } )` ;
247
+ target . style . insetInlineStart = `calc(${ horizontalScrollOffset + triggerBox . right } px - ${ position . inlineSize } )` ;
244
248
} else {
245
- target . style . insetInlineStart = `${ triggerBox . left } px` ;
249
+ target . style . insetInlineStart = `${ horizontalScrollOffset + triggerBox . left } px` ;
246
250
}
247
251
// Keep track of the initial dropdown position and direction.
248
252
// Dropdown direction doesn't need to change as the user scrolls, just needs to stay attached to the trigger.
@@ -391,18 +395,26 @@ const Dropdown = ({
391
395
}
392
396
const updateDropdownPosition = ( ) => {
393
397
if ( triggerRef . current && dropdownRef . current && verticalContainerRef . current ) {
398
+ const isIOSVirtualKeyboardPresent =
399
+ window . visualViewport ?. height && window . visualViewport . height < window . innerHeight ;
400
+
401
+ dropdownRef . current . style . position = isIOSVirtualKeyboardPresent ? 'absolute' : 'fixed' ;
402
+
403
+ const verticalScrollOffset = isIOSVirtualKeyboardPresent ? document . documentElement . scrollTop : 0 ;
404
+ const horizontalScrollOffset = isIOSVirtualKeyboardPresent ? document . documentElement . scrollLeft : 0 ;
405
+
394
406
const triggerRect = getLogicalBoundingClientRect ( triggerRef . current ) ;
395
407
const target = dropdownRef . current ;
396
408
if ( fixedPosition . current ) {
397
409
if ( fixedPosition . current . dropBlockStart ) {
398
- dropdownRef . current . style . insetBlockEnd = `calc(100% - ${ document . documentElement . scrollTop + triggerRect . insetBlockStart } px)` ;
410
+ dropdownRef . current . style . insetBlockEnd = `calc(100% - ${ verticalScrollOffset + triggerRect . insetBlockStart } px)` ;
399
411
} else {
400
- target . style . insetBlockStart = `${ document . documentElement . scrollTop + triggerRect . insetBlockEnd } px` ;
412
+ target . style . insetBlockStart = `${ verticalScrollOffset + triggerRect . insetBlockEnd } px` ;
401
413
}
402
414
if ( fixedPosition . current . dropInlineStart ) {
403
- target . style . insetInlineStart = `calc(${ triggerRect . insetInlineEnd } px - ${ fixedPosition . current . inlineSize } )` ;
415
+ target . style . insetInlineStart = `calc(${ horizontalScrollOffset + triggerRect . insetInlineEnd } px - ${ fixedPosition . current . inlineSize } )` ;
404
416
} else {
405
- target . style . insetInlineStart = `${ triggerRect . insetInlineStart } px` ;
417
+ target . style . insetInlineStart = `${ horizontalScrollOffset + triggerRect . insetInlineStart } px` ;
406
418
}
407
419
}
408
420
}
0 commit comments