+
+
+
+
+
+
diff --git a/core/src/components/popover/test/adjustment/popover.e2e.ts b/core/src/components/popover/test/adjustment/popover.e2e.ts
new file mode 100644
index 00000000000..77a0386cb32
--- /dev/null
+++ b/core/src/components/popover/test/adjustment/popover.e2e.ts
@@ -0,0 +1,32 @@
+import { expect } from '@playwright/test';
+import { test } from '@utils/test/playwright';
+
+test.describe('popover: adjustment', async () => {
+ test('should not render the popover offscreen', async ({ page }) => {
+ await page.goto('/src/components/popover/test/adjustment');
+
+ /**
+ * We need to click in an area where
+ * there is not enough room to show the popover
+ * below the click coordinates but not enough
+ * room above the click coordinates that we
+ * can just move the popover to without it going
+ * offscreen.
+ */
+ await page.setViewportSize({
+ width: 500,
+ height: 400,
+ });
+
+ const ionPopoverDidPresent = await page.spyOnEvent('ionPopoverDidPresent');
+
+ await page.mouse.click(300, 300);
+
+ await ionPopoverDidPresent.next();
+
+ const popoverContent = page.locator('ion-popover .popover-content');
+ const box = (await popoverContent.boundingBox())!;
+
+ expect(box.y > 0).toBe(true);
+ });
+});
diff --git a/core/src/components/popover/utils.ts b/core/src/components/popover/utils.ts
index 3457379591c..363db25c520 100644
--- a/core/src/components/popover/utils.ts
+++ b/core/src/components/popover/utils.ts
@@ -863,7 +863,17 @@ export const calculateWindowAdjustment = (
*/
if (triggerTop + triggerHeight + contentHeight > bodyHeight && (side === 'top' || side === 'bottom')) {
if (triggerTop - contentHeight > 0) {
- top = triggerTop - contentHeight - triggerHeight - (arrowHeight - 1);
+ /**
+ * While we strive to align the popover with the trigger
+ * on smaller screens this is not always possible. As a result,
+ * we adjust the popover up so that it does not hang
+ * off the bottom of the screen. However, we do not want to move
+ * the popover up so much that it goes off the top of the screen.
+ *
+ * We chose 12 here so that the popover position looks a bit nicer as
+ * it is not right up against the edge of the screen.
+ */
+ top = Math.max(12, triggerTop - contentHeight - triggerHeight - (arrowHeight - 1));
arrowTop = top + contentHeight;
originY = 'bottom';
addPopoverBottomClass = true;