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);
}
});