diff --git a/core/src/components/modal/modal.tsx b/core/src/components/modal/modal.tsx index eb56d50e73f..6845edcd18d 100644 --- a/core/src/components/modal/modal.tsx +++ b/core/src/components/modal/modal.tsx @@ -74,6 +74,7 @@ export class Modal implements ComponentInterface, OverlayInterface { private currentBreakpoint?: number; private wrapperEl?: HTMLElement; private backdropEl?: HTMLIonBackdropElement; + private dragHandleEl?: HTMLButtonElement; private sortedBreakpoints?: number[]; private keyboardOpenCallback?: () => void; private moveSheetToBreakpoint?: (options: MoveSheetToBreakpointOptions) => Promise; @@ -950,6 +951,18 @@ export class Modal implements ComponentInterface, OverlayInterface { } }; + /** + * When the modal receives focus directly, pass focus to the handle + * if it exists and is focusable, otherwise let the focus trap handle it. + */ + private onModalFocus = (ev: FocusEvent) => { + const { dragHandleEl, el } = this; + // Only handle focus if the modal itself was focused (not a child element) + if (ev.target === el && dragHandleEl && dragHandleEl.tabIndex !== -1) { + dragHandleEl.focus(); + } + }; + render() { const { handle, @@ -965,11 +978,13 @@ export class Modal implements ComponentInterface, OverlayInterface { const mode = getIonMode(this); const isCardModal = presentingElement !== undefined && mode === 'ios'; const isHandleCycle = handleBehavior === 'cycle'; + const isSheetModalWithHandle = isSheetModal && showHandle; return ( (this.backdropEl = el)} @@ -1021,6 +1037,7 @@ export class Modal implements ComponentInterface, OverlayInterface { aria-label="Activate to adjust the size of the dialog overlaying the screen" onClick={isHandleCycle ? this.onHandleClick : undefined} part="handle" + ref={(el) => (this.dragHandleEl = el)} > )} diff --git a/core/src/components/modal/test/sheet/index.html b/core/src/components/modal/test/sheet/index.html index 8dacb81ffc4..bc78bb10535 100644 --- a/core/src/components/modal/test/sheet/index.html +++ b/core/src/components/modal/test/sheet/index.html @@ -106,6 +106,12 @@ > Present Sheet Modal (Scroll at any breakpoint) + + + + Dismiss + Set breakpoint + + + + + `, + config + ); + + const openButton = page.locator('#open-modal'); + + const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent'); + + await openButton.click(); + await ionModalDidPresent.next(); + + const dragHandle = page.locator('ion-modal .modal-handle'); + await expect(dragHandle).toBeVisible(); + + openButton.focus(); + await expect(openButton).toBeFocused(); + + // Tab should now bring us to the drag handle + await page.keyboard.press('Tab'); + + await expect(dragHandle).toBeFocused(); + }); + }); }); diff --git a/core/src/components/modal/test/sheet/modal.e2e.ts-snapshots/modal-sheet-present-ios-ltr-Mobile-Chrome-linux.png b/core/src/components/modal/test/sheet/modal.e2e.ts-snapshots/modal-sheet-present-ios-ltr-Mobile-Chrome-linux.png index 667072054c9..18f6105e791 100644 Binary files a/core/src/components/modal/test/sheet/modal.e2e.ts-snapshots/modal-sheet-present-ios-ltr-Mobile-Chrome-linux.png and b/core/src/components/modal/test/sheet/modal.e2e.ts-snapshots/modal-sheet-present-ios-ltr-Mobile-Chrome-linux.png differ diff --git a/core/src/components/modal/test/sheet/modal.e2e.ts-snapshots/modal-sheet-present-ios-ltr-Mobile-Firefox-linux.png b/core/src/components/modal/test/sheet/modal.e2e.ts-snapshots/modal-sheet-present-ios-ltr-Mobile-Firefox-linux.png index 2e68c8b5904..d0c98a0e0db 100644 Binary files a/core/src/components/modal/test/sheet/modal.e2e.ts-snapshots/modal-sheet-present-ios-ltr-Mobile-Firefox-linux.png and b/core/src/components/modal/test/sheet/modal.e2e.ts-snapshots/modal-sheet-present-ios-ltr-Mobile-Firefox-linux.png differ diff --git a/core/src/components/modal/test/sheet/modal.e2e.ts-snapshots/modal-sheet-present-ios-ltr-Mobile-Safari-linux.png b/core/src/components/modal/test/sheet/modal.e2e.ts-snapshots/modal-sheet-present-ios-ltr-Mobile-Safari-linux.png index 45deea7faac..d7ed5b51e2e 100644 Binary files a/core/src/components/modal/test/sheet/modal.e2e.ts-snapshots/modal-sheet-present-ios-ltr-Mobile-Safari-linux.png and b/core/src/components/modal/test/sheet/modal.e2e.ts-snapshots/modal-sheet-present-ios-ltr-Mobile-Safari-linux.png differ diff --git a/core/src/components/modal/test/sheet/modal.e2e.ts-snapshots/modal-sheet-present-md-ltr-Mobile-Chrome-linux.png b/core/src/components/modal/test/sheet/modal.e2e.ts-snapshots/modal-sheet-present-md-ltr-Mobile-Chrome-linux.png index 57c051dc3d8..f5779b3f795 100644 Binary files a/core/src/components/modal/test/sheet/modal.e2e.ts-snapshots/modal-sheet-present-md-ltr-Mobile-Chrome-linux.png and b/core/src/components/modal/test/sheet/modal.e2e.ts-snapshots/modal-sheet-present-md-ltr-Mobile-Chrome-linux.png differ diff --git a/core/src/components/modal/test/sheet/modal.e2e.ts-snapshots/modal-sheet-present-md-ltr-Mobile-Firefox-linux.png b/core/src/components/modal/test/sheet/modal.e2e.ts-snapshots/modal-sheet-present-md-ltr-Mobile-Firefox-linux.png index 5583effec90..c6b1e70af3d 100644 Binary files a/core/src/components/modal/test/sheet/modal.e2e.ts-snapshots/modal-sheet-present-md-ltr-Mobile-Firefox-linux.png and b/core/src/components/modal/test/sheet/modal.e2e.ts-snapshots/modal-sheet-present-md-ltr-Mobile-Firefox-linux.png differ diff --git a/core/src/components/modal/test/sheet/modal.e2e.ts-snapshots/modal-sheet-present-md-ltr-Mobile-Safari-linux.png b/core/src/components/modal/test/sheet/modal.e2e.ts-snapshots/modal-sheet-present-md-ltr-Mobile-Safari-linux.png index 16d727246b3..6146a575086 100644 Binary files a/core/src/components/modal/test/sheet/modal.e2e.ts-snapshots/modal-sheet-present-md-ltr-Mobile-Safari-linux.png and b/core/src/components/modal/test/sheet/modal.e2e.ts-snapshots/modal-sheet-present-md-ltr-Mobile-Safari-linux.png differ