From 0ad731756c3a9ba8a7eb9deb6f152ff5827cb23f Mon Sep 17 00:00:00 2001 From: Ronni Skansing Date: Wed, 27 May 2026 21:40:01 +0200 Subject: [PATCH] fix actions dropdown position Signed-off-by: Ronni Skansing --- .../table/TableDropDownEllipsis.svelte | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/frontend/src/lib/components/table/TableDropDownEllipsis.svelte b/frontend/src/lib/components/table/TableDropDownEllipsis.svelte index a29d192..659068f 100644 --- a/frontend/src/lib/components/table/TableDropDownEllipsis.svelte +++ b/frontend/src/lib/components/table/TableDropDownEllipsis.svelte @@ -25,13 +25,23 @@ document.addEventListener('keydown', handleGlobalKeydown); activeFormElement.set(dropdownId); // set this as active, closing others - const viewportHeight = window.innerHeight; - const viewportWidth = window.innerWidth; + // Use clientWidth/clientHeight (excludes scrollbars, matches CSS layout) rather than + // window.innerWidth which can report stale or incorrect values after client-side navigation + // when the page previously had horizontal overflow (e.g. navigating from dashboard). + const viewportHeight = document.documentElement.clientHeight; + const viewportWidth = document.documentElement.clientWidth; const buffer = 20; const minHeight = 64; const maxHeight = 400; const gap = 8; + // Capture scroll offsets so we can express the final position in document coordinates. + // position:absolute (relative to initial containing block) requires document coords, + // which avoids the position:fixed quirk where body overflow-x:auto can cause the + // containing block to shift after cross-page navigation (e.g. dashboard → filters). + const scrollX = window.scrollX || document.documentElement.scrollLeft || 0; + const scrollY = window.scrollY || document.documentElement.scrollTop || 0; + const buttonRect = buttonRef.getBoundingClientRect(); const spaceAbove = buttonRect.top - buffer; @@ -40,6 +50,7 @@ const availableSpace = shouldShowAbove ? spaceAbove : spaceBelow; const optimalHeight = Math.min(Math.max(availableSpace, minHeight), maxHeight); + // Calculate in viewport coordinates first, then clamp to viewport bounds. const menuWidth = 256; const spaceOnRight = viewportWidth - buttonRect.right - buffer; menuX = spaceOnRight >= menuWidth ? buttonRect.left : buttonRect.right - menuWidth; @@ -56,7 +67,8 @@ menuY = buttonRect.bottom + gap; } - menuRef.style = `left: ${menuX}px; top: ${menuY}px; max-height: ${optimalHeight}px`; + // Convert viewport coordinates to document coordinates for position:absolute. + menuRef.style = `left: ${menuX + scrollX}px; top: ${menuY + scrollY}px; max-height: ${optimalHeight}px`; } }; @@ -140,7 +152,7 @@