fix(searchable-select): reposition portal on scroll/resize

Adds scroll (capture) and resize listeners so the fixed-position dropdown
tracks its trigger as the page scrolls.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Hardik 2026-05-31 06:49:49 +05:30
parent 2057fc2d8d
commit 2c912caedb

View file

@ -34,13 +34,12 @@ export function SearchableSelect({
useEffect(() => { setMounted(true); }, []);
// Recalculate portal position whenever the dropdown opens
useLayoutEffect(() => {
if (!open || !containerRef.current) return;
// Recalculate portal position on open, scroll, and resize so the panel tracks
// the trigger even when the page (or any ancestor) is scrolled.
const updatePortalPos = useCallback(() => {
if (!containerRef.current) return;
const rect = containerRef.current.getBoundingClientRect();
const PANEL_WIDTH = 420;
// Prefer right-aligning with the trigger; clamp so it doesn't go off-screen left
const right = window.innerWidth - rect.right;
const left = Math.max(8, rect.right - PANEL_WIDTH);
setPortalStyle({
position: "fixed",
@ -49,7 +48,23 @@ export function SearchableSelect({
width: PANEL_WIDTH,
zIndex: 9999,
});
}, [open]);
}, []);
useLayoutEffect(() => {
if (!open) return;
updatePortalPos();
}, [open, updatePortalPos]);
useEffect(() => {
if (!open) return;
// capture:true catches scroll on any ancestor, not just window
window.addEventListener("scroll", updatePortalPos, true);
window.addEventListener("resize", updatePortalPos);
return () => {
window.removeEventListener("scroll", updatePortalPos, true);
window.removeEventListener("resize", updatePortalPos);
};
}, [open, updatePortalPos]);
// Close on outside click / Escape
useEffect(() => {