diff --git a/.changeset/fix-popper-anchor-positioning.md b/.changeset/fix-popper-anchor-positioning.md new file mode 100644 index 000000000..b8d79e56f --- /dev/null +++ b/.changeset/fix-popper-anchor-positioning.md @@ -0,0 +1,5 @@ +--- +'@radix-ui/react-popper': patch +--- + +Fixed `Popper.Anchor` positioning when `PopoverAnchor` and `PopoverTrigger` coexist as siblings or with CSS absolute positioning diff --git a/apps/storybook/stories/popover.stories.tsx b/apps/storybook/stories/popover.stories.tsx index 7aaca1343..a6d2dd7a8 100644 --- a/apps/storybook/stories/popover.stories.tsx +++ b/apps/storybook/stories/popover.stories.tsx @@ -267,6 +267,38 @@ export const CustomAnchor = () => ( ); +export const CustomAnchorSibling = () => ( + + + Item + + + open + + + + close + + + +); + export const WithSlottedTrigger = () => { return ( diff --git a/packages/react/popper/src/popper.tsx b/packages/react/popper/src/popper.tsx index efb8cc26b..1695d065b 100644 --- a/packages/react/popper/src/popper.tsx +++ b/packages/react/popper/src/popper.tsx @@ -77,15 +77,13 @@ const PopperAnchor = React.forwardRef( const ref = React.useRef(null); const composedRefs = useComposedRefs(forwardedRef, ref); - const anchorRef = React.useRef(null); React.useEffect(() => { - const previousAnchor = anchorRef.current; - anchorRef.current = virtualRef?.current || ref.current; - if (previousAnchor !== anchorRef.current) { - // Consumer can anchor the popper to something that isn't - // a DOM node e.g. pointer position, so we override the - // `anchorRef` with their virtual ref in this case. - context.onAnchorChange(anchorRef.current); + // Consumer can anchor the popper to something that isn't + // a DOM node e.g. pointer position, so we override the + // `anchorRef` with their virtual ref in this case. + const desiredAnchor = virtualRef?.current || ref.current; + if (context.anchor !== desiredAnchor) { + context.onAnchorChange(desiredAnchor); } });